- Java中所有继承都是公有继承
- this是当前对象的引用,而super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字
/*
以下代码可以成功编译运行
*/
class Employee{
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Manager extends Employee{
public Manager(String name) {
super(name);
}
public Employee getManager() {
return this;
}
}
/*
以下代码编译出错
*/
class Employee{
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Manager extends Employee{
public Manager(String name) {
super(name);
}
public Employee getManager() {
return super;
}
}
- 如果子类的构造器没有显示地调用超类的构造器,则将自动调用超类默认(没有参数)的构造器
/*
以下代码报错,因为父类Employee没有无参构造器
*/
class Employee{
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Manager extends Employee{
public Manager(String name) {
// super(name);
}
public Employee getManager() {
return this;
}
}
- 关键字this的两个用途:一是引用隐式参数;二是调用该类的其他构造器(此时调用构造器的语句只能作为另一个构造器中第一条语句出现)
- 关键字super的两个用途:一是调用父类的构造器;二是调用父类的方法
- 根据引用对象变量实际引用的对象类型,正确调用相应的方法
- 一个对象变量可以指示多种实际类型的现象称为多态;在运行时能够自动地选择调用哪个方法的现象称为动态绑定
- 在继承层次中,从某个特定的类到其祖先的路径被称为该类的继承链
- 在进行动态绑定时,如果一个引用变量的声明类型(父类型)与它所指向对象的实际类型(子类型)不同,那么这个引用变量只能调用子类型中那些与父类公有的方法,无论是直接继承而来还是覆盖重写(在此对书本P156第4)点提出质疑),如果调用的是子类新定义的方法,那么程序将会报错。佐证代码如下:
/*
父类Employee中并没有setBonus方法,而staff的声明类型是Employeee,因此在编译staff.setBonus()时出错
*/
public class Test {
public static void main(String[] args){
Manager m1 = new Manager("sc");
Employee staff= new Employee("scc");
staff = m1;
staff.setBonus(1000);//出错
System.out.println(staff.getBonus());
}
}
class Employee{
private String name;
private int bonus = 0;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
// public void setBonus(int bonus) {
// this.bonus = 0;
// }
public int getBonus() {
return bonus;
}
}
class Manager extends Employee{
private int bonus = 0;
public Manager(String name) {
super(name);
}
public void setBonus(int bonus) {
this.bonus = bonus;
}
public int getBonus() {
return bonus;
}
}
- 在子类覆盖父类的某个方法时,允许子类将覆盖方法的返回类型定义为原返回类型的子类型(仍为覆盖)
- 如果是private方法、static方法或者final方法或者构造器,那么无法动态绑定无法调用这些方法,此时应为静态绑定
- 在覆盖一个方法时,子类方法不能低于超类方法的可见性。特别:如果超类方法时public,子类覆盖该方法时必须声明为public
- final:阻止类继承;阻止方法被覆盖;阻止实例域被修改
- 将一个类声明为final,只有其中的方法自动地成为final(类都不能被继承,何谈方法覆盖),而不包括域。代码佐证如下:
/*
以下代码输出结果为:
5
6
表明了虽然A是final类,但是A.a并不是final型
*/
public class Test1 {
public static void main(String[] args) {
new A().test();
}
}
final class A{
public int a = 5;
public final int b = a;
public void test() {
System.out.println(a);
a++;
System.out.println(a);
}
}
- 如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程称为内联。例如,内联调用e.getName()将被替换为访问e.name域
- a instanceof A:判断a所指向的对象是否是A的实例
- abstract:
- abstract方法不能写方法实现(实现留给子类或者子类将该方法再声明为abstract或者子类本身声明为abstract)
- 包含abstract方法的类必须被声明为abstract
- 声明为abstract的类中可以包含通用方法(即非abstract,有实现体的方法)
- 声明为abstract的类不能创建对象实例(即不能使用new操作)
- abstract不能与private、static、final、native并列修饰同一个方法。因为若方法为private,则该方法无法被继承,自然也就无法被实现;若方法为static、final或者native(native不太懂),则应该写清楚方法的实现体(不写清方法体怎么让类或者对象调用),与abstract矛盾
- 若要调用abstract类中的static方法,直接使用类名.方法名即可;若要调用abstract类中其它非static非abstract的方法,则可使用子类对象,然后强制转成父类对象,再调用abstract类中相应方法即可。佐证代码如下:
/*
输出结果为:
print1
print2
*/
public class Test1 {
public static void main(String[] args) {
A a = new B();
a = (A) a;
a.print1();
A.print2();
}
}
abstract class A{
public abstract void test();
public static void print2() {
System.out.println("print2");
}
public void print1() {
System.out.println("print1");
}
}
class B extends A{
@Override
public void test() {
// TODO Auto-generated method stub
}
}
- 用于控制可见性的4个访问修饰符:
- 仅对本类可见------private
- 对所有类可见------public
- 对本包和所有子类可见------proteced
- 对本包可见------默认,不需要修饰符
- 在Java中,只有基本类型(八大基本类型)不是对象
- Object类中equals方法判断的是两个对象是否具有相同的引用。若其中一个对象为null,则会报NullPointerException
- Objects(注意有个s)类中的静态方法equals(obj1,obj2)可比较obj1和obj2至少有一个null的情况下obj1和obj2是否相等。若obj1和obj2都是null,则返回true;若只有一个null,则返回false;若都不是null,则判断obj1和obj2是否是指向同一个对象
- equals方法应具有下面的特性:
- 自反性。即x.equals(x)应返回true
- 对称性。即x.equals(y)应与y.equals(x)返回同样的结果
- 传递性。即若x.equlas(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true
- 一致性。如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果
- 对于任意非空引用x,x.equals(null)应该返回false
- 对于P169关于编写一个完美的equals方法的建议第4)点,理解如下:如果每个子类对于equals的结果都有一样的比较标准(比如说都是比较名字,薪水,id),那么只需要判断每个子类的父类是不是都是同一个,其中书上的className应该是父类的类名;如果equals的比较标准在子类中有所改变(子类对于父类的equals进行了重写覆盖),那么首先应该判断当前比较的对象是不是同一个类(因为它们的各自的equals方法比较的标准可能都不相同)。佐证代码如下:
/*
子类Manager和Boss并没有重写父类Employee的equals方法
因此当执行m1.equals(b)以及b.equals(m1)时将继续调用父类
的equals方法判断。此时父类equals使用的一个判断条件是判断显示参数
obj是否为Employee的实例,且只是判断了name和salary是否一样
*/
public class Test {
public static void main(String[] args){
Manager m1 = new Manager("sc", 100, 1);//id=1
Boss b = new Boss("sc", 100, 10);//id=10
System.out.println(m1.equals(b));//true
System.out.println(b.equals(m1));//true
}
}
class Employee{
public String name;
public int salary;
public int id;
public Employee(String name,int salary,int id) {
// TODO Auto-generated constructor stub
this.name = name;
this.salary = salary;
this.id = id;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(this == obj) return true;
if(obj == null || !(obj instanceof Employee)) return false;
Employee other = (Employee) obj;
return name.equals(other.name) && salary == other.salary;
}
}
class Manager extends Employee{
public Manager(String name,int salary,int id) {
// TODO Auto-generated constructor stub
super(name, salary, id);
}
}
class Boss extends Employee{
public Boss(String name,int salary,int id) {
// TODO Auto-generated constructor stub
super(name, salary, id);
}
}
如果子类Manager改写了从父类继承来的equals方法,那么子类的equals方法中应该使用判断条件getClass而不是继续使用instanceof。此时,Boss类的equals方法也应该重写(因为得满足equals的对称性)。佐证代码如下:
/*
在子类改写的equals方法中,不仅比较名字,薪水是否一样,还比较了id是否一样
*/
public class Test {
public static void main(String[] args){
Manager m1 = new Manager("sc", 100, 1);
Boss b = new Boss("sc", 100, 10);
System.out.println(m1.equals(b));//false
System.out.println(b.equals(m1));//false
}
}
class Employee{
public String name;
public int salary;
public int id;
public Employee(String name,int salary,int id) {
// TODO Auto-generated constructor stub
this.name = name;
this.salary = salary;
this.id = id;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(this == obj) return true;
if(obj == null || !(obj instanceof Employee)) return false;
Employee other = (Employee) obj;
return name.equals(other.name) && salary == other.salary;
}
}
class Manager extends Employee{
public Manager(String name,int salary,int id) {
// TODO Auto-generated constructor stub
super(name, salary, id);
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(this == obj) return true;
if(obj == null || getClass() != obj.getClass()) return false;
Manager other = (Manager) obj;
return name.equals(other.name) && salary == other.salary && id == other.id;
}
}
class Boss extends Employee{
public Boss(String name,int salary,int id) {
// TODO Auto-generated constructor stub
super(name, salary, id);
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(this == obj) return true;
if(obj == null || getClass() != obj.getClass()) return false;
Boss other = (Boss) obj;
return name.equals(other.name) && salary == other.salary && id == other.id;
}
}
- hashCode()方法默认返回的是对象的地址
- 如果重新定义equals方法,那么就必须重新定义hashCode方法。并且equals方法与hashCode方法的定义必须一致:如果x.equals(y)返回true,那么x.hashCode()就必须与y.hashCode()具有相同的值。代码如下:
public class Test {
public static void main(String[] args){
Manager m1 = new Manager("sc", 100, 1);
Boss b = new Boss("sc", 100, 10);
System.out.println(m1.equals(b));//true
System.out.println(m1.hashCode() + " " + b.hashCode());//114645 114645
}
}
class Employee{
public String name;
public int salary;
public int id;
public Employee(String name,int salary,int id) {
// TODO Auto-generated constructor stub
this.name = name;
this.salary = salary;
this.id = id;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(this == obj) return true;
if(obj == null || !(obj instanceof Employee)) return false;
Employee other = (Employee) obj;
return name.equals(other.name) && salary == other.salary;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return Objects.hash(name,salary);//使用Objects的静态方法hash()返回多个参数的散列码组合
}
}
class Manager extends Employee{
public Manager(String name,int salary,int id) {
// TODO Auto-generated constructor stub
super(name, salary, id);
}
// @Override
// public boolean equals(Object obj) {
// // TODO Auto-generated method stub
// if(this == obj) return true;
// if(obj == null || getClass() != obj.getClass()) return false;
// Manager other = (Manager) obj;
// return name.equals(other.name) && salary == other.salary && id == other.id;
// }
}
class Boss extends Employee{
public Boss(String name,int salary,int id) {
// TODO Auto-generated constructor stub
super(name, salary, id);
}
// @Override
// public boolean equals(Object obj) {
// // TODO Auto-generated method stub
// if(this == obj) return true;
// if(obj == null || getClass() != obj.getClass()) return false;
// Boss other = (Boss) obj;
// return name.equals(other.name) && salary == other.salary && id == other.id;
// }
}
- Arrays.toString():打印一维数组元素 Arrays.deepToString():打印多维数组元素
- java.lang.Object中:native Class getClass():返回类信息 java.lang.Class中: Class getSuperclass():返回当前类的超类信息 String getName():返回当前类的具体名称信息(包括包名) String getSimpleName():返回当且类名(不包括包名)
- List中的set只能修改数组中已经存在的元素!!!
ArrayList<Integer> list = new ArrayList<>();
list.set(0, 1);
System.out.println(list.get(0));//IndexOutOfBoundsException
- List转成数组并打印数组
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(i);
}
Integer[] a = new Integer[list.size()];//不能写int,必须是Integer,泛型不支持基本类型
a = list.toArray(a);//P181书上写的是list.toArray(a) 如果按书上写的,假如a.length() < list.size(),那么操作结束后,a将不会有任何变化,每个元素都是null(因为a每个元素是Integer(int的对象形式???))
System.out.println(Arrays.toString(a));
- 装箱:int --> Integer 拆箱:Integer -->int
- 对于boolean、byte、char<=127以及介于-128~127之间的short和int,如果两个变量Integer a,Integer b的值在此范围并且相等,那么a==b的结果将是true;否则a==b为false
Integer a = 100;
Integer b = 100;
System.out.println(a == b);//true
Integer c = 128;
Integer d = 128;
System.out.println(c == d);//false
- 包装器类引用可以为null
Integer a = null;
System.out.println(a);//null
- 反射(没搞明白,先跳过)