java对象和类:对象和类的基本概念、构造函数和初始化顺序等

对象和类

基本概念

类、对象、实例、构造、封装、实例字段、方法、状态、继承、对象的行为、状态、标识、类之间的关系依赖、耦合、继承。

static静态字段和静态方法

  • 静态字段也被称为类字段,在类第一次被加载的时候创建
  • 静态方法不能访问实例字段,而可以访问静态字段。

final关键字

  • final修饰基本类型或者不可变类
  • final修饰可变类时,只是引用不可变,但是引用的对象可变。

构造函数

  • 构造函数通过new来调用,不可以直接调用。
  • 重载
    • 重载解析
    • 返回类型不是数字签名的一部分
    • 默认有无参数构造器,但是定义了构造器之后,默认的无参数构造器失效

初始化顺序

  • 先初始化静态字段、代码块
    • 静态字段、代码块按照定义的顺序初始化
  • 然后初始化字段、初始化块
    • 字段、初始化块按照定义的顺序初始化
  • 最后初始化构造函数
    • 先初始化调用的构造函数。
    • 然后从上往下依次初始化。

代码习惯

  • 工厂方法
  • 不要返回可变对象
  • aClassName
  • 不要用对象调用静态方法,而应该用类
  • 每个对象都可以有个main,用来单元测试。
  • 方法不需要访问对象或者方法只需要访问静态字段的时候可以使用静态方法。

零碎知识点

  • java按引用传递
  • System.out.setout()可以将System.out设置为不同的流。因为它是原生方法,可以绕过java访问控制机制。
  • 一个方法可以访问所属类的所有对象的私有数据。
  • 所有java对象都是在堆中调用的。
  • 访问器方法和更改器方法
  • 变量不是对象,创建变量的时候还没有对象,更像是创建了指向对象的指针。

  • 包名
  • 域名逆序-项目名-类名
  • 只能用import导入一个包,而不能多个包
  • 命名冲突时需要import使用的类或者加入完整的包名来指定某个包
  • import static 导入静态方法和静态字段,不只是类
  • 编译器处理文件(文件分割符和java扩展名)、解释器加载类(点分隔符)。
  • 没有修饰符,同一个包中可以访问。

继承

基本概念

  • super调用父类
  • private不可被继承
  • 多态和动态绑定
  • 父类变量可以引用子类对象,并且可以使用父类的方法,并自动分辨是子类还是父类的。
  • 父类变量不可以使用子类的方法。
  • 子类会覆盖和父类相同签名的方法。
  • 可协变的返回类型:子类方法的返回类型是父类同签名方法返回类型的子类。
  • 静态绑定:private、static、final、构造器。
  • 动态绑定:子类到超类
  • 方法表查表
  • 子类覆写方法的时候,不能低于超类方法的可见性。
  • final
    • 不允许扩展
    • final类中所有方法自动为final方法
    • 方法也可以被声明为final,不允许被覆盖
    • final类中所有字段不会被声明为final
    • final可以加快速度。内联调用可以加快速度。而继承会干扰优化。
  • 超类转化为子类
  • 抽象类
    • 抽象类变量可以引用非抽象子类对象
    • 抽象类不可以实例化
    • 如果子类没有完全实现抽象方法,子类也是抽象类
  • protected
    • 所有子类和同一个包中的所有其它类都可见。
  • 默认(不加修饰符)
    • 对本包可见。

Object

equals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
**建议的equals写法
*/
public boolean equals(Object other) { //接受Object对象
if(this == other) return true; //检测是否是同一个

if(other == null) return false; //如果另一个是空

if(getClass() != otherObject.getClass()) return false; //比较是否是同一个对象
//if(!(other instanceof ClassName)) return false; //比较是否是子类

ClassNmae other = (ClassName)other; //强制类型转换。

return field1 == field2 //基本类型
&& Objects.equals(field2, other.field2) //对象
&& . . .;
}
  • 数组可以用Array.equals来检测对应元素是否相等。

hashCode

  • Object的hashCode是通过存储地址得出
  • String的hashCode是通过字符串内容得出。(内容相同的字符串,散列码相同)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Employee {
private String name;
private double salary;
private LocalDate hireDay;

public int hashCode() {
return 7 * name.hashCode() //调用字段的hashCode
+ 11 * new Double(salary).hashCode() //基本类型包装下
+ 13 * hireDay.hashCode();
}

/*
** 如果null,返回9
** 静态方法Objects.hashCode()避免创建double对象
*/
public int hashCode() {
return 7 * Objects.hashCode(name)
+ 11 * Objects.hashCode(salary)
+ 13 * Objects.hashCode(hireDay);
}

public int hashCode() {
return Objects.hash(name, salary, hireDay);
}
}
  • equals与hashCode定义必须相容,即equals为true的hashCode必须相等。

toString

1
2
3
4
5
6
7
8
9
10
public String toString() {
return getClass().getName() //这样使用可以给子类复用。
+ "[field1=" + field1
+ . . .
+ "]";
}

"" + x; //可以自动转换为toString()

System.out.println(Arrays.toString(array)); //数组打印的方法。

泛型

ArrayList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ArrayList<ClassName> v = new ArrayList<ClassName>();

var v = new ArrayList<ClassName>();

ArrayList<ClassName> v = new ArrayList<> (); //菱形语法

v.add();
v.ensureCapacity(n);
ArrayList<ClassName> v = new ArrayList<>(n);

v.trimToSize();

v.set(i, value); //v[i] = value;
v.get(i); //v[i]

  • ArrayList和vector
  • 与老版本不带类型的ArrayList交互

对象包装器与自动装箱

  • 包装器类不可变,不可派生
  • 自动装箱、自动拆箱

参数数量可变

1
public Printstream printf(String fmt, Object... args) {return format(fmt, args);}

枚举类

enum

反射

暂时略

接口

  • 接口用来描述类应该做什么,而不是指定他们怎么做
  • 一个类可以实现一个或多个接口
  • 接口不会有实例字段
  • java8之前,接口不会实现方法。
  • interface和implements
  • 接口声明默认public
  • 接口字段默认为public static final