本博客只用于个人查漏补缺
类、超类、子类
子类构造器
- 使用super关键字调用构造器的语句必须是子类构造器的第一条语句
- 子类的构造器没有显示的调用超类的构造器,将自动的调用超类的无参构造
如果超类没有无参构造,并且在子列的构造器中没有显式的嗲用超类的其他构造器,Java编译器会报错 - 动态绑定:对象变量在运行时自动的选择适当的方法
- 静态绑定:如果是private,static,final方法,编译器将准确的知道该调用那个方法,不依赖于隐式参数的类型
继承层次
- 继承层次:一个公共超类派生出来的所有类的集合
- 继承链:继承层次中,某个特定的类到其祖先的路径
理解方法调用
- 重载解析:编译器确定方法调用中提供的参数类型,在所有方法名为 f 的方法中搜索一个与所提供的参数类型完全匹配的方法,就选择这个方法
- 虚拟机预先为每一个类计算了一个方法表,其中列出了所有方法的签名和要调用的实际方法,这样在查找时,虚拟机只要查这个表就可以了
- 运行时,调用 e.getSalary() 的解析过程为:
虚拟机获取 e 的实际类型的方法表,根据具体对象
接下来,虚拟机查找定义了 getSalary() 签名的类
最后,虚拟机调用这个方法 - 注意:覆盖一个方法时,子类方法不能低于超类方法的可先性,
例如:超类方法为public,子类方法就必须为public
阻止继承:final类和方法
- 不允许被扩展的类成为final类
- 不允许被覆盖的方法被声明为final
- 如果一个类声明为final,那么其中的方法自动成为final,不包括字段
- 方法或类声明为final的原因:确保不会在子类中被改变语义
如:Calendar类中getTime和setTime,这表明Calendar类负责Date类与日历状态的转换,而不允许子类来添乱;String类为final类,意味着不允许任何人定义String的子类 - 内联(inlining) 如果一个方法没有被覆盖并且很短,编译器会对它进行优化处理
如:e.getName() 将被替换成访问字段 e.name - 如果方法很简短,被频繁调用并且没被覆盖,那么即时编译器会将该方法进行内联处理
如果虚拟机加载了另一个类,而这个子类覆盖了一个内联方法,优化器将取消这个方法的内联。
抽象类
- 即使不包含抽象方法,也可以将类声明为抽象类
- 抽象类不能实例化
- 可以定义一个抽象类的对象变量,但这个变量只能引用非抽象子类的对象(类似多态)
访问控制修饰符小结
- private:仅对本类可见
- 默认:对本包可见
- protected:对本包和所有子类可见
- public:对外部完全可见 Object:所有类的超类 Object类型的变量
- Java中,只有基本类型:数值,字符,布尔, 不是对。所有的数组类型,不管是对象数组还是基本类型的数组都扩展了Object类
### equals方法 - 使用
Object.equals(a, b)
可以防止两个参数都为null的情况,如果都为null,返回true,如果一个为null,返回false,如果都不为null 调用a.equals(b)
java.util.Arrays
static boolean equals(xxx[] a, xxx[] b)
如果两个数组长度相同,并且对应位置元素相同,返回true,或者都为null也返回true
hashCode方法
- 由于hashCode()方法定义在Object类中,每个对象都有一个默认的散列码,其值由对象的存储地址得出
- equals 与 hashCode的定义必须相容:如果 x.equals(y) 返回true,那么 x.hashCode() 就必须等于 y.hashCode()
- Object.hashCode(a) 如果a 为null,返回0,否则返回a.hashCode()
- Object.hash(x1, x2, x3)是对各个参数调用Object.hashCode,并组合这些散列值
- Arrays.hashCode()方法计算一个散列码,散列码由数组元素的散列码组成
泛型数组列表
- Java允许运行时确定数组大小,C/C++中必须在编译时就确定整个数组的大小
- ArrayList 如果已经知道或者能够估计数组可能存储的元素数量,就可以在填充数组之前调用
ensureCapacity(定义的长度)
方法,此方法将调用分配一个包含指定对象数量的内部数组,在加入新元素时只要不超过这个数量就不用多次重新分配空间
或者将初始容量创给ArrayList构造器ArrayList<Integer> a = new ArrayList<>(100);
trimToSize()
将存储块的大小调整为保存当前元素数量所需要的空间
对象包装器与自动装箱
- 拆箱和装箱是编译器要做的工作,不是虚拟机,编译器在生成类的字节码时会插入必要的方法调用,虚拟机只是执行这些字节码
参数数量可变的方法
- Object… 参数类型 与 Object[] 完全一样
- 也就是说,允许将数组作为最后一个参数传递给有可变参数的方法
- 如果一个已有方法的最后一个参数是数组,可以吧它重新定义为有可变参数的方法,而不会破坏任何已有的代码
反射
Class类
Java运行时系统会为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类
可以使用一个特殊的Java类访问这些信息,保存这些信息的类名为Class
- 获得一个Class类型的实例的方法:
- Object类中的getClass()方法会返回一个Class类型的实例
- 使用静态方法 forName()获得类名对应的Class对象
- T是任意的Java类型或Java关键字,T.Class 将代表匹配的类对象
- 注意:一个Class对象实际上表示的是一个类型,可能是类,也可能不是类,如 int 不是类,但 int.class 是一个Class类型的对象
- 虚拟机为每一个类型管理一个唯一的Class对象,可以利用 == 运算符实现两个类对象的比较
如:if(e.getClass() == Employ.class)
- Class类型的对象嗲用 getConstructor 方法将得到一个Constructor类型的对象,然后使用 newInstance 方法构造一个实例
如果这个类没有无参构造,那么将会抛出一个异常 - Class类中的 getFields、getMethods和getConstructors方法将分别返回类支持的公共字段、方法和构造器的数组,包括超类的成员
- 而 getDeclareFields …只能返回类中声明的全部字段….不包括超类的成员