第七章

第七章 面向对象高级特性

  • 单词的意思
  • 可以修饰什么
  • 修饰后有什么变化

7.1 final

final: 最终的

用法

  • 修饰类
    使类无法被继承, 没有子类
  • 修饰方法
    这个类无法被重写
  • 修饰变量
    使变量值无法修改

内部变量用final后一定要赋值, 否则会报错

7.2 native

native: 本地的, 原生的

用法

  • 只能修饰方法
    表示这个方法体代码不是用java语言实现的
    可以正常调用或者重写这部分代码

7.3 static

native: 本地的, 原生的

用法

  • 方法
    不能被重写
    其他类中可以直接类名.方法名调用
    静态方法不允许出现this, super, 非静态修饰的成员
  • 变量
    值是该类对象共享的
    静态变量的get/set也是静态的
    与局部变量变量名相同可以用 类名.静态变 量区分
  • 内部类
  • 代码块

7.4 静态代码块

[修饰符] class 类名{
	static{
		静态代码块;
	}
}

作用

协助完成类初始化, 可以为类变量赋值

类初始化

类初始化有

  • 静态变量的显式赋值代码
  • 静态代码块中的代码
  • 按顺序执行

类初始化执行特点

  • 每个类的<clinit>()只执行一次
  • 父类没初始化会先初始化父类
  • 先类初始化才能实例初始化

7.5 变量的分类和区别

  • 按数据类型划分
    • 基本数据类型
    • 引用数据类型
  • 按声明类型的不同
    • 成员变量
    • 局部变量

成员变量和局部变量的区别

  • 声明位置不同
    • 成员变量: 类中方法外
    • 局部变量: 形参列表, 方法内, 代码块中
  • 修饰符不同
    • 成员变量: 4种权限修饰符, static, final...
    • 局部变量: 只有final
  • 生命周期
    • 成员变量
      • 静态变量和类生命周期相同
      • 费静态变量(实例变量)和所属的对象相同
    • 局部变量: 每次都是新的
  • 作用域
    • 成员变量
      • 静态变量可以在本类中随意使用, 在其他类可以用 类名.变量 名使用
      • 非静态变量在本类只能被非静态成员中使用, 在其他类中用对象名.变量名使用
    • 局部变量
      • 有作用域

7.6 根父类

java.lang.Object类是所有类的父类, 包括数组对象

  • Object方法是所有类的父类, 所有的方法都会被继承到子类中
  • 每一个对象创建, 都会调用到Object的实例初始化方法<init>()
  • Object类型的变量, 形参, 数组都可以存储任意类型的对象

Object类的常用方法

  • public String toString();
    • 返回对象的字符串表示形式
    • 建议所有子类重写此方法。
    • Object 类的 toString 方法返回一个字符串, 该字符串由类名, @, 和此对象哈希码的无符号十六进制表示组成
    • getClass().getName() + '@' + Integer.toHexString(hashCode())
  • public final Class<?> getClass()
    • 获取对象运行时的类型
  • protected void finalize()
    • 当对象被GC确定要被回收的垃圾, 在回收之前GC会调用这个方法. 而且这个方法只会被调用一次, 子类可以选择重写
  • public int hashCode()
    • 此方法是为了提高哈希表的性能.
    • hashCode 的常规协定
      • hashCode值不相等, 两个对象不会相等
      • hashCode相等, 两个对象有可能相等
  • public boolean equals(Object obj)
    • 指示其他某个对象是否与此对象“相等”.
    • 默认情况下, 此方法等价于"==", 比较的是对象的地址值
    • 可以重写
      • 当此方法被重写时, 通常有必要重写 hashCode 方法, 以维护 hashCode 方法的常规协定, 该协定声明相等对象必须具有相等的哈希码。
    • equals 方法在非空对象引用上实现相等关系
      • 自反性: 对于任何非空引用值 x, x.equals(x) 都应返回 true。
      • 对称性: 对于任何非空引用值 x 和 y, 当且仅当 y.equals(x) 返回 true 时, x.equals(y) 才应返回 true。
      • 传递性: 对于任何非空引用值 x、y 和 z, 如果 x.equals(y) 返回 true, 并且 y.equals(z) 返回 true, 那么 x.equals(z) 应返回 true。
      • 一致性: 对于任何非空引用值 x 和 y, 多次调用 x.equals(y) 始终返回 true 或始终返回 false, 前提是对象上 equals 比较中所用的信息没有被修改。
      • 对于任何非空引用值 x, x.equals(null) 都应返回 false。

7.7 abstract

抽象方法类
当不能确定方法体如何实现, 也要体现子类的共同特征, 就要用抽象方法
如果一个类有抽象方法, 那么这个类是抽象方法类

[权限修饰符] abstract class 类名 [extends 父类]{
	[权限修饰符] abstract 返回值 方法名();
	//抽象方法没有方法体
}

抽象类的特点

  • 不能直接实例化, 即new对象
  • 抽象类就是用来继承的, 子类如果不重写所有的抽象方法, 那么这个子类也是抽象类
  • 抽象类有构造器, 用于子类实例化过程调用
  • 抽象类也可以没有抽象方法, 目的是无法创建对象而是创建子类对象
  • 可以多态引用

不能和abstract一起使用的修饰符

  • final 不能一起修饰方法和类
  • static 不能一起修饰方法
  • native 不能一起修饰方法
  • private 不能一起修饰方法和类

7.8 接口

一种标准, 注意关注行为标准(即方法)
开发原则有一条, 面向接口编程

声明

[修饰符] interface 接口名{
	接口的成员列表;
}

实现

[修饰符] class 实现类 implements 父接口们{
}
[修饰符] class 实现类 extends 父类 implements 父接口们{
}

接口继承

[修饰符] interface 接口名 extends 父接口们{
	接口的成员列表;
}

接口特点

  • 接口不能直接实例化, 即不能直接new对象
  • 可以与子类多态引用
  • 实现类在实现接口时必须重写所有抽象方法, 除非这个类是抽象类
  • Java规定单继承, 但接口可以多继承
  • 接口与接口也可以多继承

接口成员

  • JDK1.8前
    • 全局静态常量: public static final, 这些修饰符可以省略
    • 公共抽象方法: public abstract 也可以省略
  • JDK1,8后
    • 公共静态方法: public static 不能省略
public interface Flyable{
	long MAX_SPEED = 7900000;
	void fly();
}
public class bird implements Flyable{
	void fly(){
		//......
	}
}

7.9 内部类

声明在另外一个类里面就是内部类

内部类的形式

  • 静态内部类
  • 非静态成员内部类
  • 有名字的局部内部类
  • 匿名内部类

匿名内部类

//匿名内部类中调用父类的构造器
new 父类(){
	内部类成员列表
}
new 父类(实参列表){
	内部类成员列表
}

// 接口没有构造器, 这里是匿名内部类自己的无参构造, 默认调用根父类Object的无参构造
new 父接口名(){
	内部类成员列表
}

匿名内部类, 匿名对象的区别?

System.out.println(new Student("张三"));//匿名对象
 
Student stu = new Student("张三");//这个对象有名字, stu

//既有匿名内部类, 又是一个匿名的对象
new Object(){
	public void test(){
		//.....
	}
}

//这个匿名内部类的对象, 使用obj这个名字引用, 对象有名字但是这个类没有名字
Object obj = new Object(){
	public void test(){
		//.....
	}
}

使用

  • 继承

    abstract class Father{
    	public abstract void test();
    }
    
    public class Test {
    	public static void main(String[] args) {
    		//多态引用
    		Father f = new Father() {
    			@Override
    			public void test() {
    				System.out.println("用匿名内部类继承了Father这个抽象类, 重写了test方法");
    			}
    		};
    	}
    }
    
  • 实现

    interface Flyable{
    	void fly();
    }
    
    public class Test {
    	public static void main(String[] args) {
    		//用父接口与匿名内部类的对象构成了多态引用
    		Flyable f = new Flyable() {
    			@Override
    			public void fly() {
    				System.out.println("用匿名内部类继承了Flyable这个抽象类, 重写了抽象方法");
    			}
    		};
    		f.fly(); 
    	}
    }
    

示例代码

  • 用匿名内部类对象直接调用方法

    new Object(){
    	public void test(){
    		System.out.println("用匿名内部类的匿名对象直接调用方法");
    	}
    }.test();
    
  • 用匿名内部类对象直接作为实参

    Value[] all = new Value[3];
    all[0] = new Value(20);
    all[1] = new Value(23);
    all[2] = new Value(21);
    
    Arrays.sort(all, new Comparator(){
    	public int compare(Object o1, Object o 2){
    		Value v1 = (Value)o1;
    		Value v2 = (Value)o2;
    		return v1.getValue() - v2.getValue();
    	}
    })
    

常用接口

  • java.lang.Comparable: 自然排序
    抽象方法: int compareTo(Object obe)

  • java.util.Comparator: 定制排序
    抽象方法: int compare(Object obj1, Object obj2)

    public class Value implements Comparable{
    	private int value;
    
    	@Override
    	public int compareTo(Object arg0) {
    		Value v1 = (Value)arg0;
    		return this.value - v1.value;
    	}
    	
    	public Value(int value) {
    		super();
    		this.value = value;
    	}
    	public Value() {
    		super();
    	}
    	public int getValue() {
    		return value;
    	}
    	public void setValue(int value) {
    		this.value = value;
    	}
    	@Override
    	public String toString() {
    		return "Value [value=" + value + "]";
    	}
    }
    
  • 如果后面又发现新的需求, 选择定制排序, 实现Comparable接口

静态内部类

[修饰符] class 外部类名 [extends 父类] [implements 父类接口们]{
	[其他修饰符] static class 静态内部类 [extends 父类] [implements 父类接口们]{
		\\静态内部类的成员列表..
	}

	\\外部类的其他成员列表..
}
  • 包含的成员
    • 可以包含类的所有成员
  • 修饰符要求
    • 四种权限修饰符
    • 其他修饰符: abstract, final
  • 使用外部类的成员上是否有要求
    • 只能使用外部类的静态成员
  • 在外部类使用静态内部类是否有要求
  • 在外部类的外面使用静态内部类是否有要求
    • 如果使用静态内部类的静态成员
      • 外部类名.静态内部类名.静态成员
    • 如果是用的是静态内部类的非静态成员
      • 先创建静态内部类的对象
      • 内部类名.静态内部类 对象名 = 外部类名.静态内部类名([实参列表]);
      • 通过对象调用非静态成员
      • 对象名.XXX
  • 字节码文件形式: 外部类名$静态内部类名.class

非静态内部类

[修饰符] class 外部类名 [extends 父类] [implements 父类接口们]{
	[其他修饰符] class 非静态内部类 [extends 父类] [implements 父类接口们]{
		\\非静态内部类的成员列表..
	}

	\\外部类的其他成员列表..
}
  • 包含的成员
    • 不允许出现静态成员
  • 修饰符要求
    • 四种权限修饰符
    • 其他修饰符: abstract, final
  • 使用外部类的成员上是否有要求
    • 都可以使用
  • 在外部类使用非静态内部类是否有要求
    • 在外部类的静态成员中不能使用非静态内部类
  • 在外部类的外面使用静态内部类是否有要求
    • 使用非静态内部类的非静态成员
      • 外部类名 外部类对象名 = new 外部类名([实参列表]);
      • 外部类名.非静态内部类名 对象名 = 外部类对象名.new 非静态内部类名([实参列表]);
        外部类名.非静态内部类名 对象名 = 外部类对象名.get非静态内部类对象的方法([实参列表]);
      • 对象名.XXX
  • 字节码文件形式: 外部类名$非静态内部类名.class

局部内部类

[修饰符] class 外部类名 [extends 父类] [implements 父类接口们]{
	[修饰符] 返回值类型 方法名([实参列表]){
		[其他修饰符] class 局部内部类 [extends 父类] [implements 父类接口们]{
			\\局部内部类的成员列表..
		}
	}

	\\外部类的其他成员列表..
}
  • 包含的成员
    • 不允许静态成员
  • 修饰符要求
    • 权限修饰符: 不可用
    • 其他修饰符: abstract, final
  • 使用外部类的成员上是否有要求
    • 使用外部类的静态成员: 都可以用
    • 使用外部类的非静态成员: 所在的方法是不是静态的
    • 使用所在方法的局部变量: 必须是final修饰
  • 在外部类使用局部内部类是否有要求
    • 有作用域
  • 在外部类的外面使用局部内部类是否有要求
    • 无法使用
  • 字节码文件形式: 外部类名$编号局部内部类名.class
posted @ 2020-02-24 22:36  烟熏咸鱼干  阅读(131)  评论(0编辑  收藏  举报