4.1 源文件的声明

package:指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。package 顶层包名.子包名;

import:引入指定包层次下所需要的类或全部类(.*)。import 包名.类名

源文件声明规则

  1. package com.java.example;
  2. import ....;
  3. import ...;
  4. public MyClass{ // 一个源文件中只能有一个 public 类且源文件的名称应该和 public 类的类名保持一致。
  5. }

4.2 类和对象

Java程序是一系列对象的集合,这些对象通过调用彼此的方法来协同工作。

  • 类:描述一类对象的行为和属性。
  • 对象:类的一个实例,是实实在在的某个物体。

匿名对象:不定义对象的名称,直接调用对象方法。如new Person().shout();。使用情形如下:

  • 某对象仅调用一次方法
  • 作为方法实参

    4.3 Java方法

    方法是类或对象行为特征的抽象,用来完成某个操作。封装的目的是实现代码重用。在Java中方法必须定义在类中。

4.3.1 可变参数

Java一个方法只能指定一个可变参数,它必须是方法的最后一个参数,其可传入任意长度数组或任意个指定类型参数。数组仅可传入任意长度数组,不可为任意个指定类型参数。

  1. public static void test(int a ,String[] books); // 这里的两种方法由于参数相同,不能重载
  2. public static void test(int a ,String books);
  3. test(123,new String[]{"123","456","789"}); // 可以调用方法1和方法2
  4. test(123,"123","456","789"); // 仅可调用方法2
  5. test(123); // 仅可调用方法2

4.3.2 值传递机制

  • 形参是基本数据类型:将变量的“数据值”传递给形参,函数内改变变量数据不改变原有数据值。
  • 形参是引用数据类型:将变量的“地址值”传递给形参,函数内改变变量数据将改变原有数据值。

    4.3.3 构造方法

    当一个对象被创建时候,至少要调用一个构造方法来初始化该对象。所有的类都有构造方法,如果没有显式地为类定义构造方法,Java 编译器将为该类提供一个不带任何参数的默认构造方法。

默认构造方法的访问修饰符和类的访问修饰符相同。一旦定义了自己的构造方法,默认构造方法就会失效。父类的构造器不会被子类继承。

  1. public class Person{
  2. public Person(String name, int age, Date d) {this(name,age);…} // 调用重载的构造方法
  3. public Person(String name, int age) {…}
  4. public Person(String name, Date d) {…}
  5. public Person(){…}
  6. }

4.3.4 this关键字

调用当前类的属性、方法和构造器,如果在本类中未找到,会在父类中查找。当在方法内使用,其意为该对象的引用。

  1. this(); //调用本类的无参数构造器,必须定义在类构造器首行
  2. this(name); //调用本类的其他有参数构造器,必须定义在类构造器首行
  3. this.name = name; // 调用本类属性,通常用this来区分同名属性和局部变量
  4. this.speak(); // 调用方法

4.3.5 static关键字

有时我们希望无论产生多少对象,某些特定的内容仅保留一份,让所有实例共享,则使用static关键字。

将这些属性设置为类属性,方法设置为类方法。类方法无需创建对象就可调用。static方法只能访问类的static属性或方法,不可访问非static结构,也不可使用this和super关键字。

4.3.6 代码块

代码块用于对类或对象进行初始化,仅可由static修饰。

  • 静态代码块:
    1. 不可以调用非静态的属性和方法。
    2. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
    3. 静态代码块的执行要先于非静态代码块。
    4. 静态代码块随着类的加载而加载,且只执行一次。
  • 非静态代码块:
    1. 可以调用非静态的属性和方法。
    2. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
    3. 每次创建对象的时候,都会执行一次。且先于构造器执行。
      1. class Person {
      2. public static int total;
      3. static {
      4. total = 100;
      5. System.out.println("in static block!");
      6. }
      7. }
      程序中成员变量赋值的执行顺序:
  1. 默认初始化
  2. 显式初始化、多个初始化块依次被执行
  3. 构造器成员进行初始化操作
  4. 通过”对象.属性”或”对象.方法”给属性赋值

    4.4 面向对象特征—封装

    程序设计追求“高内聚,低耦合”,也就是说,隐藏对象内部的复杂性,只对外公开简单的接口:

    • 高内聚 :类内部的数据操作细节由类自己完成,不允许外部干涉;
    • 低耦合 :仅对外暴露少量的方法用于调用。
修饰符 当前类 同一包内 子孙类(同一包) 子孙类(不同包) 其他包
public Y Y Y Y Y
protected Y Y Y Y/N N
default Y Y Y N N
private Y N N N N

class的权限修饰符仅能用public和default。Java中通过定义private属性与publicget、set方法来提高代码的可维护性,隐藏类内部的细节。

4.5 面向对象特征—继承

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,多个类无需再定义这些属性和行为,只要继承那个类即可。父类更通用,子类更具体。合理的使用继承会大大减少代码量,同时便于维护,提高代码复用性。

  • 继承的特性:
    • 子类拥有父类非 private 的属性、方法。子类使用super调用父类属性、方法。
    • 子类可以拥有自己的属性(同名属性也可,不会覆盖父类属性)和方法,即子类可以对父类进行扩展。
    • 重写方法仅可被声明为相同或更高权限,且返回值类型不可大于父类方法返回值类型。
    • Java 的继承是单继承,final声明的类不可继承
    • 子类不继承父类的构造方法的。如果父类存在无参构造器,系统会自动调用父类的无参构造器,否则必须在子类的构造方法中显式地通过 super 调用父类的构造方法或者通过this调用本类的其他构造方法。
    • 子类即父类,但父类不是子类。 | this | super | | —- | —- | | 访问本类中的属性,若本类没有则从父类中继续查找 | 直接访问父类中的属性 |

重载(overloading) 是在一个类里面,方法名字相同,而参数个数、类型、类型顺序不同。、

重写(override)是子类中存在与父类中方法名字,参数与返回值均相同的方法。

方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

区别点 重载方法 重写方法
参数列表 必须修改 一定不能修改
返回类型 可以修改 一定不能修改
异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常
访问 可以修改 一定不能做更严格的限制(可以降低限制)

4.6 面向对象特征—多态

对象的多态性:父类的引用指向子类的对象,是一种运行时行为。

多态存在的三个必要条件:继承、重写、父类引用指向子类对象。作用是为了提高代码的通用性,常称作接口重用。

使用多态时,引用变量不能访问子类中添加的属性和方法,仅能调用子类的重写方法,成员变量不具备多态性。

4.7 Object类

Object类是所有Java类的根父类。如果在类的声明中未指明其父类,则默认父类为java.lang.Object

  1. public Object() //构造器
  2. public boolean equals(Object obj) // 对象比较
  3. public int hashCode() // 取得Hash码
  4. public String toString() // 对象打印时调用
  • ==equals的区别:
    基本数据类型没有区别。对于引用类型,==比较内存地址,equals默认也是比较内存地址,但可以重写。
  • toString()
    String与其它类型数据连接时,其他类型自动调用toString(),可以根据需要在自定义类型中重写toString()方法 ```java Date now = new Date(); System.out.println(“now=”+now); // 相当于“now=”+now.toString() System.out.println(now); // 相当于s1.toString()

public void test() { char[] arr = new char[] { ‘a’, ‘b’, ‘c’ }; System.out.println(arr);//打印abc,字符串底层也是使用字符数组实现的 int[] arr1 = new int[] { 1, 2, 3 }; System.out.println(arr1);//打印内存地址 double[] arr2 = new double[] { 1.1, 2.2, 3.3 }; System.out.println(arr2);//打印内存地址 }

  1. <a name="iLQXm"></a>
  2. ## 4.8 抽象类与接口
  3. <a name="aAjt0"></a>
  4. ### 4.8.1 抽象类
  5. > 将易变的不确定部分抽象出来让子类去实现。
  6. 抽象类不能实例化对象,所以抽象类必须被继承。类的其它功能如,成员变量、成员方法、构造方法的访问方式和普通类一样。
  7. `abstract` 声明**抽象类或抽象方法**,抽象方法只包含方法名,而没有方法体。`public abstract double computePay();`
  8. 如果一个类包含抽象方法,那么该类必须是抽象类。任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
  9. <a name="YZDYi"></a>
  10. ### 4.8.2 接口
  11. 使用接口的情景:
  12. 1. 从几个类中派生出一个子类,继承它们所有的方法和属性。
  13. 1. 从几个类中抽取出一些共同的行为特征,而又非是不是的关系。
  14. 接口是一组规范,体现的是“能不能”的关系,而继承体现的是“是不是”的关系。类描述对象的属性和方法,接口则包含类要实现的方法。接口可以理解为一种特殊的类。
  15. 接口`interface`是抽象方法和常量值的集合,接口也可继承其他接口。除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。接口可用来声明一个变量,成为一个空指针,引用一个以此接口实现的对象。<br />`class SubClass extends SuperClass implements InterfaceA{ }`
  16. 接口的特性:
  17. - 接口没有构造方法,不能实例化对象;
  18. - 接口支持多继承;
  19. - 接口中每一个方法是隐式抽象的,无需自己指定为abstract;
  20. - 接口中的变量会被隐式的指定为 public static final 变量,无需自己指定;
  21. Java8中,可以为接口添加静态方法和默认方法。
  22. - **静态方法:**使用 static 关键字修饰。仅可通过接口直接调用静态方法。
  23. - **默认方法:**默认方法使用 default 关键字修饰。可以通过实现类对象来调用。
  24. 子类继承了两个接口,若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法,会出现:**接口冲突。**解决办法就是实现类必须覆盖接口中同名同参数的方法,来解决冲突。
  25. 子类继承了父类和接口,接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:**类优先原则。**
  26. <a name="w3tY8"></a>
  27. ### 4.8.3 抽象类和接口的区别
  28. 1. 抽象类中的方法可以有方法体,但是接口中的方法不行。
  29. 1. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  30. 1. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
  31. ```java
  32. [可见度] interface 接口名称 [extends 其他一个或多个接口名]
  33. { // 声明变量与抽象方法 }

在Java开发中90%使用的都是接口,抽象类往往只是实现一个过渡。如果你拥有一些方法并且想让它们中的一些有默认实现,使用抽象类。如果想实现多重继承,那么你必须使用接口,让子类强制实现。

  1. // 调用接口的默认方法
  2. Filial.super.help(); // 接口名.super.方法名;

4.9 内部类

当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整结构又仅为外部事物提供服务,那么整个内部的完整结构最好使用内部类。

  • 成员内部类:直接声明在外部类内,与成员变量同级,有访问限制符
    • static成员内部类
    • 非static成员内部类
  • 局部内部类:声明在方法内、代码块内、构造器内(无访问修饰符)

成员内部类可以调用外部类的所有成员;声明为static时不能再使用外层类的非static的成员变量。可以声明为abstract类 ,因此可以被其它的内部类继承;也可以声明为final,表示此类不能被继承。
注意:

  1. 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。
  2. 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”
  3. 成员内部类可以直接使用外部类的所有成员,包括私有的数据
  4. 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的
    1. // 实例化成员内部类对象
    2. // 静态成员内部类
    3. Person.Dog dog = new Person.Dog();
    4. // 非静态成员内部类
    5. Person person = new Person();
    6. Person.Cat cat = person.new Cat();
    7. // 内部类调用外部类的方法
    8. //内部类与外部类重名
    9. Person.this.name
    10. //内部类与外部类无重名
    11. name
    局部内部类只在声明它的方法或代码块中使用,而且是先声明后使用,其作用域、地位、使用方式均与局部变量相同。
    1. // 返回一个实现了Comparable接口的类对象
    2. public Comparable getComparable(){
    3. // 方法1:创建一个实现了Comparable接口的类:局部内部类
    4. class MyComparable implements Comparable{
    5. public int compareTo(Object o){
    6. return 0;
    7. }
    8. }
    9. return new MyComparable();
    10. // 方法2:
    11. return new Comparable(){
    12. public int compareTo(Object o){
    13. return 0;
    14. }
    15. }
    16. }