public class Manager extends Employee
{
}
Java中,所有的继承都是公有继承,没有C++中的私有继承和保护继承。
//java
public double getSalary()
{
double baseSalary=super.getSalary();
return baseSalary+bonus;
}
//c++
public:
double getSalary()
{
double baseSalary=Employee::getSalary();
return baseSalary+bonus;
}
在Java中,方法默认是动态绑定的,不需要声明为virtual。如果不希望方法有虚拟特性,可以将其标记为final的。
使用super调用父类构造函数的语句必须出现在子类构造函数的第一句。
//java
public Manager(String name,double salary,int year, int month,int day)
{
super(name,salary,year,month,day);
bonus=0;
}
//c++
Manager(String name,double salary,int year,int month,int day)
:Employee(name,salary,year,month,day),bonus(0){
}
如果子类没有显示地调用父类的构造函数,将会调用父类的默认构造函数,如果父类没有默认构造函数,编译器将报错。
在构造函数中,可以使用this.调用其它构造函数,该语句也必须出现在第一句,并且不能和super语句同时出现,否则编译器将报错。
Manager[] managers=new Manager[10];
Employee[] staff=managers;
staff[0]=new Employee();
该语句编译可以通过,但是我们将一个父类对象赋给了一个子类的引用,当使用managers[0].setBonus(1000)的时候,用到了一个不存在的成员变量。
x.f(param);
Java调用方法的过程如下:
首先,如果x的类型为C,编译器将列举出C类型所有名为f的方法,以及其父类中访问属性为public名为f的方法。
第二步,根据参数列表的类型,从所有名为f的方法中筛选出参数列表符合的方法,(过程中可能涉及到类型转换)。如果编译器没有找到与参数类型匹配的方法,或者发现经过类型转换后有多个方法与之匹配,就会报告一个错误。
第三步,如果是private、static、final、或者构造函数,那么编译器可以准确知道该调用哪个方法,这称为静态绑定。
第四步,如果是需要动态绑定的方法,虚拟机会调用与x所引用对象的实际类型最合适的那个方法。假设x的实际类型是D,它是C的子类,如果D类中定义了方法f()且参数类型符合,就直接调用它。否则将在D类的父类中寻找合适的f()。虚拟机预先为每个类创建一个方法表(method table),包括了该类所有的方法和该类的父类所有的方法都在方法表中,在调用该类的方法时直接搜索该类的方法表就知道该调用哪个方法。如果使用了super关键字,将会在父类的方法表中搜索方法。
在覆盖一个方法时,子类方法不能低于超类方法的可见性,如果超类方法是public,子类就一定要是public。
final使用位置 | 作用 |
---|---|
成员变量声明前 | 该成员变量不可修改(相当于const) |
方法声明前 | 不可以被覆盖 |
类声明前 | 不可以被继承,其中的方法也默认是final的,但变量不是。 |
Java的内联是由编译器自动处理的。
修饰符 | 可见性 |
---|---|
private | 仅本类中可见 |
protected | 本包和所有子类中可见 |
public | 所有类可见 |
默认(不需要修饰符) | 本包可见 |
特性 | 意义 |
---|---|
自反性 | x.equals(x)应返回true |
对称性 | x.equals(y)和y.equals(x)应返回同样的结果 |
传递性 | 如果x.equals(y)&&y.equals(z),则x.equals(z) |
一致性 | 如果x、y引用的对象不变,则x.equals(y)不变 |
非空性 | 如果x非空,则x.equals(null)返回false |
//显式参数命名为otherObject
public boolean equals(Object otherObject)
{
//检测this与otherObject是否引用到同一个对象
if(this==otherObject) return true;
//检测otherObject是否为null
if(otherObject==null) return false;
//比较this与otherObject是否属于同一个类。如果equals的语义在每个子类中有所改变,就使用getClass检测
if(getClass()!=otherObject.getClass()) return false;
//如果所有的子类都拥有统一的语义,就使用instanceof检测
if(!(otherObject instanceof ClassName)) return false;
//将otherObject转换为相应的类类型变量
ClassName other=(ClassName)otherObject;
//比较所有需要比较的域
return field1==other.field1&&.......;
//如果在子类中重新定义了equals,就首先调用super.equals(other);
}
public int hashCode()
{
//将会返回三者的hashCode组合后的结果
return Objects.hash(name,salary,hireDay);
}
public String toString()
{
return getClass().getName()
+"[name="+name
+",salary"+salary
+",hireDay"+hireDay
+"]";
}
ArrayList
有时,需要将int这样的基本类型转换为对象,例如:声明ArrayList
基本类型 | 包装器类型 |
---|---|
int | Integer |
long | Long |
floar | Float |
double | Double |
short | Short |
byte | Byte |
char | Character |
void | Void |
boolean | Boolean |
意味着方法可接受的参数数量可变,printf就是一个可变参数方法,其定义如下。
public class PrintStream
{
public PrintStream printf(String fmt,Object...args){return format(fmt,args);
}
其中Object…是java语法的一部分,表示这个方法可以接受任意数量的对象。
下面一段代码用于计算若干个double数据的最大值:
public static double max(double...values)
{
double result=Double.NEGATIVE_INFINITY;
for(double x:values) result=result>x?result:x;
return result;
}
public enum Size{SMALL,MEDIUM,LARGE,EXTRA_LARGE};