第六章 面向对象(下)

包装类

  • 通过包装类将八种基本类型的值包装成对象使用
  • 自动装箱:把基本类型变量赋给对应包装类变量
  • 自动拆箱:把包装类变量赋给对应基本类型变量
  • 自动装箱拆箱必须类型匹配,赋给Object是利用了向上转型特性
  • 包装类的parseXxx(String s)方法和Xxx(String s)构造器将字符串转换成基本类型
  • String类重载valueOf()方法将基本类型转换成字符串
  • 包装类实例可以与数值类型的值比较
  • 两个包装类引用指向同一个对象时才相等
  • 包装类的compare(xxx val1, xxx val2)方法比较基本类型值大小,布尔值true>false

处理对象

  • syso打印会自动toString(),可用于对象的自我描述,所有类都可以重写toString()
  • 引用变量指向同一对象时==才会true
  • ==只能用于比较有继承关系的两个对象
  • new String("hello");共产生两个字符串对象
  • jvm使用常量池保存"hello"
  • 调用String构造器创建新对象,新"hello"被保存在堆内存
  • jvm常量池保证相同字符串常量只有一个
  • String的equal()已经重写了,字符序列相同返回true
  • 默认Object的equal()只是比较地址,需要时可重写提供自定义相等标准
  • if(obj!=null && obj.getClass()==Person.class)当obj是Person对象时

类成员

  • static不能修饰构造器
  • null对象可以访问类成员,因为会在底层转换为类去访问
  • 单例类,只能创建一个对象,private修饰构造器,public static方法作为类的访问点,static成员变量保存层创建的对象

final

  • final可修饰类、变量、方法
  • 修饰成员变量,必须显示指定初始值,不能重新赋值
  • 类变量:静态初始化块或声明时指定初始值
  • 实例变量:非静态初始化块、构造器或声明时指定
  • 修饰局部变量,只能赋值一次,final修饰的形参不能在代码块里赋值
  • 修饰引用变量时不能改变的是地址,对象可以改变
  • 直接量,变量其实不存在,编译时宏替换
  • final修饰变量
  • 定义时确定初始值
  • 初始值编译时能确定
  • final修饰的方法不能被重写
  • private final同时修饰重写其实是创建新方法
  • final修饰类不能被继承
  • 不可变类:创建实例后,其实例变量不可改变
  • 创建不可变类:
  • private final修饰成员变量
  • 带参数构造器用来初始化成员变量
  • 不能提供setter方法
  • 有必要时重写hashCode()和equals(),保证equals()相等时haahCode()也相等
  • 类的引用变量实例改变时属于可变类,在构造器和getter方法中使用创建新对象的方法实现真正不可变类
  • Integer的valueOf缓存,范围导致不在范围的不被缓存,能缓存的同值对象则返回同一地址

抽象类

  • 抽象方法abstract修饰,不能有方法体,圆括号后一个分号
  • 有抽象方法的类必须定义成抽象类,抽象类里可以没有抽象方法
  • 抽象类不能被实例化,只能被继承
  • 抽象类的构造器不能用于创建实例,只能被子类调用
  • 抽象类更好发挥多态优势,父类变量调用子类实现后的抽象方法时无须转换为子类类型
  • abstract和final不共存
  • abstract和static不能同时修饰方法,可以同时修饰内部类
  • abstract和private不能同时修饰方法
  • 模板模式,车速表
  • 抽象父类抽象不能实现的方法
  • 父类定义通用算法,其它依赖于子类去实现

接口

  • public/default interface修饰,public修饰时与源文件同名
  • 接口只能继承接口,多继承
  • 成员可以是静态常量、抽象方法、内部类、接口、枚举、默认方法和类方法
  • 接口所有成员都是public访问权限,可省略
  • 系统自动为静态常量增加public static final
  • 抽象方法自动修饰为public abstract
  • 默认方法必须用default修饰,不能用static,自动public修饰
  • 类方法必须用static修饰,不能用default,子的钱public修饰
  • 内部类、内部接口、内部枚举自动oublic static
  • 实现类可实现多个接口,implements,必须实现接口的所有抽象方法,否则需要定义成抽象类
  • 实现抽象方法时注意加上public
  • 接口引用变量可以直接赋给Object引用变量
  • 简单工厂模式


  • 命令模式


内部类

  • 作用
  • 提供更好的封装,不允许其他类访问
  • 直接访问所在外部类的私有数据
  • 匿名内部类创建只需要使用一次的类
  • 内部类多可用private、protected、static修饰符
  • 非静态内部类不能拥有静态成员
  • 内部类也会生成.class文件OuterClass$InnerClass.class
  • 非静态内部类内可直接访问外部类的private成员
  • 非静态内部类的对象里会保存它所寄生的外部类对象的引用
  • 覆盖的成员变量可以用OuterClass.this.、this.作区分
  • 外部类不能直接使用非静态内部类成员,必须显式创建对象来调用
  • 外部类的静态成员不能直接使用非静态内部类
  • 非静态内部类中不能定义静态成员
  • 静态内部类可以包含静态成员,也可以包含非静态成员
  • 静态内部类内部不能访问外部类的实例成员,只能访问外部类的类成员,因为静态内部类持有外部类的引用,没有外部类对象的引用
  • 外部类不能直接访问静态内部类的成员,可以用内部类的类名作调用者来访问
  • 接口内可以定义内部类,默认用public static修饰
    所以接口的内部类只能是public访问权限并且是静态的
  • 在外部类以外的地方创建内部类引用变量:PackageName.OuterClass.InnerClass varName
    需要完整的类名
  • 在外部类以外的地方创建非静态内部类之前需要先创建外部类对象,在用外部类的实例作调用者调用内部类构造器new Out().new In();
  • 创建非静态内部类的子类的时候要保证子类构造器能够调用内部类的构造器,也就是必须存在一个外部类对象,参数传进子类构造器,out.super();调用内部类构造器
  • 内部类子类对象一样需要保留其父类所在外部类对象的引用
  • 创建静态内部类对象时无须创建外部类对象,因为它是类相关的,只需要把类名写全调用内部类构造器就可以了
  • 使用静态内部类只需要把外部类看做包空间,比较简单,程序需要时,优先考虑静态内部类
  • 不存在子类继承外部类去重写内部类,因为内部类类名还由外部类类名组合构成,不可能做到两个类的内部类是一样的名字,所以不能重写
  • 局部内部类不能使用访问修饰符,因为一定不能被其他类访问
  • 创建匿名内部类时会立即创建一个该类的实例,类定义立即消失
  • 匿名内部类必须继承一个父类,或实现一个接口
    new 实现接口()|父类构造器(实参列表){内部类实体部分}
  • 匿名内部类不能是抽象类,因为会随即创建对象
  • 匿名内部类不能定义构造器,因为没有类名
  • 通过父类继承创建的匿名内部类会拥有和父类相同形参列表的构造器
  • 如果局部变量被匿名内部类访问,变量就需要用final修饰,不能重复赋值
  • Lambda简化创建只有一个抽象方法的接口(函数式接口)的实例
  • (形参列表)->{代码块}
  • 如果只有一条语句,可以省略花括号,如果有返回值且只有一条语句,可以省略return关键字,会自动返回唯一语句的值
  • 允许省略形参类型,如果形参只有一个,可以省略圆括号
  • 函数式接口可以包含多个默认方法、类方法,但只能有一个抽象方法
  • Lambda表达式结果被当成对象,所以可以赋值,只能为函数式接口创建对象,也可以通过函数式接口强制类型转换,再赋值
  • Lambda实现的匿名方法的形参列表必须和函数式接口的唯一抽象方法形参列表相同
  • 如果Lambda表达式中只有一条语句,可以使用方法引用和构造器引用


    第六章 面向对象(下)_第1张图片
  • Lambda表达式可以直接访问final局部变量和外部成员变量
  • 匿名内部类可以为任意接口、抽象类、普通类创建实例,Lambda只能是函数式接口
  • Lambda限制代码块不能调用接口中定义的默认方法,匿名内部类可以

枚举类

  • 一个java源文件最多定义一个public enum,且源文件名与枚举类类名相同
  • enun默认继承java.lang.Enum,未继承Object类,不能显式继承其他类
  • 非抽象enun默认用final修饰,不能派生子类
  • 枚举类构造器默认private修饰,且只能private 修饰
  • 所有实例在第一行列出 否则永远不能产生实例,自动public static final修饰
  • 访问枚举类某实例:EnumClass.variable
  • switch语句的表达式可以是枚举值
  • values()方法返回枚举类的所有实例
  • 枚举类通常应该设计成不可变类,成员变量用private final修饰,在构造器中指定初始值,列出枚举类实例时传入参数:枚举值("实参"),……
  • 实现接口的枚举类可以让每个枚举值分别去实现抽象方法,枚举值("实参"){...抽象方法(){}...}
  • 抽象枚举类不用final修饰,用abstract修饰
  • 实现接口的枚举值实际上是枚举类的匿名子类的实例
  • 定义了抽象方法的枚举类不能用abstract修饰,因为枚举类需要显式创建枚举值,而不是父类,定义每个枚举值时必须实现抽象方法

对象与垃圾回收

  • 垃圾回收机制只负责回收堆内存中的对象
  • 程序无法控制垃圾回收的运行,只能控制对象不被引用,不能控制何时被回收
  • 垃圾回收机制回收对象之前会调用finalize()方法,该方法可能使让对象复活,让一个新的引用变量引用该对象,导致垃圾回收机制取消
  • 对象的三种状态
  • 可达状态 有一个或一个以上引用变量引用它
  • 可恢复状态 没有引用变量引用,开始调用finalize()方法
  • 不可达状态 没有引用,finalize()也已经调用
  • 被其他类的类变量引用的对象,只有类被销毁,对象才会进入可恢复状态
  • 被其他对象的实例变量引用的对象,只有当对象被销毁,才进入可恢复状态
  • 强制系统垃圾回收(只是通知)
  • System.gc() System类的静态方法gc()
  • Runtime.getRuntime().gc() Runtime对象的实例方法gc()
  • java命令的-verbose:gc可以看到每次垃圾回收后的提示信息
  • finalize()方法返回后,对象消失,垃圾回收机制开始执行
  • 永远不要主动调用某对象的finalize()方法,应该交给垃圾回收机制去调用
  • finalize()何时被调用、是否被调用具有不确定性
  • JVM执行finalize()出现异常时,垃圾回收机制不会报告异常,程序继续执行
  • 因为finalize()不一定会被调用,所以想清理某个类里打开的资源时,不要放在finalize()里
  • 引用类型
  • 强引用,最常见的普通引用方式
  • 软引用,通过SoftReference类来实现,对于只有软引用的对象来说,当系统内存空间不足时,系统可能会回收它,软引用通常用于对内存敏感的程序中
  • 弱引用,通过WeakReference类来实现,对于只有弱引用的对象,当垃圾回收机制运行时,不管系统内存空间是否足够,总会回收其所占内存
  • 虚引用,通过PhantomReference类来实现,完全类似于没有引用,主要用于跟踪对象被垃圾回收的状态,不能单独使用,必须和引用队列(ReferenceQueue)联合使用
  • 三种引用类都有get()方法,用于获取被他们所引用的对象(虚引用获取不到)
  • 联合使用软引用、弱引用和引用队列时,在对象回收之后,将把对应引用添加到关联的引用队列。虚引用则是在回收之前添加,使得可以在回收之前采取行动
  • 程序可以通过检查与虚引用关联的引用队列中是否包含该虚引用,从而了解对象的状态
  • 从软、弱引用中取出被引用的对象时,可能该对象已经被释放了

修饰符的适用范围

第六章 面向对象(下)_第2张图片
  • strictfp用来精确浮点
  • native修饰方法引入C语言实现,会失去跨平台性
  • 4个访问控制符互斥
  • abstract final不共存
  • abstract static不能同时修饰方法,可以同时修饰内部类
  • abstract private不能同时修饰方法,可以同时修饰内部类
  • private final同时修饰方法合理但无意义

你可能感兴趣的:(第六章 面向对象(下))