类的继承
Java会给每个对象分配非静态属性的内存,但是方法,无论是不是静态,都只在内存中存在一份。
Java中继承使用关键字extends。 Java中允许子类的属性和父类的同名,此时子类中包括两个重名的属性,即两个属性都存在于子类中。如果不加任何修饰,默认子类中访问的是子类定义的属性。如果想访问超类的属性,可以使用super关键字。
子类要覆盖超类的方法,必须将方法名、参数表、返回值和被覆盖的方法一模一样。覆盖方法的访问权限必须不能比被覆盖方法严格。如父类中一个方法的访问权限为protected,则子类中覆盖方法的访问权限必须是protected或者是public。
子类不能覆盖父类的final关键字或者static关键字修饰的方法。和属性的调用一样,可以使用super关键字访问父类的方法。
Object类
Object类是所有类的超类,定义了所有类都拥有的一些方法,如下:
- public final Class getClass();
- public String toString();
- public boolean equals(Object obj);
- protected Object clone();
- public int hashCode();
- public void finalize() throw Throwable
- 实际上,equals() 判断两个对象的引用是否指向同一个对象,即两个对象是否是同一个对象。这一点和==运算符实现的是同一个功能。实际上,我们使用equals()方法有时事项比较两个对象是否是同一个类,且属性值相等。这才是真正意义上的“相等”,而不是“同一”。如字符串类就覆盖了equals()方法,返回的结果就是字符串的内容是否相等,而不是是否是同一个对象,我们可以自己覆盖equals(方法)来实现自己想要的功能。
- toString()方法之前说过,返回 类名@对象的hashcode
- hashCode()方法返回一个对象的散列码。Java语言规定两个引用指向同一个对象,则两个引用的hashCode()方法返回的散列码相同;但是不强制指向不同的对象,两个引用的散列码不同;且不要求两次代码执行的同一个引用的散列码相同。Java只规定了散列码这样的要求,没有规定具体的实现方法。
- clone()方法返回一个克隆的对象。且覆盖clone方法的时候需要实现Cloneable接口。
- finalize()方法在内存回收的时候自动调用,里面实现了垃圾回收的一些功能。当需要覆盖finalize()方法的时候,需要在方法的最后调用super.finalize(),以便实现完整的垃圾回收机制。
- getClass()方法返回对象所属的类。getClass()方法是被final关键字修饰的,不能重写。可以试想通过Class对象查询类的各种信息。
Object中还定义了3个和线程相关的方法,且都是final方法,notify,notifyAll,wait。
final类和final方法
final类不能被继承;final方法不能被重写;final属性必须立即初始化,初始化以后不允许修改。
抽象方法
定义了抽象方法的类必须定义为抽象类,即方法被abstract关键字修饰,则类也必须被abstract关键字修饰。
抽象方法的声明:
[public] abstract <returnType> <methodName>(…);
抽象方法仅有方法原型,没有方法体。
泛型
Java中的泛型和C++中的模板类似,泛型方法在方法声明的时候传入类型参数,这样可以在编译时指定类型,从而使得程序更加通用且减小程序员的负担。一个典型的泛型类代码如下
class GeneralType <Type>{
Type obj;
public GeneralType(Type obj){this.obj = obj;}
public Type getObj(){
return obj;
}
}
public class Test {
public static void main(String[] args){
GeneralType<Integer> t = new GeneralType<Integer>(2);
GeneralType<Double> d = new GeneralType<Double>(4.3d);
System.out.println(t.getObj());//2
System.out.println((Double) d.getObj());//4.3
}
}
其次,还可以在类中的方法前指定通配符,这样即得到泛型方法。典型的例子如下
class GeneralMethod{
<Type> void printClassName(Type obj){
System.out.println(obj.getClass().getName());
}
}
public class Test {
public static void main(String[] args){
GeneralMethod c = new GeneralMethod();
c.printClassName(3L);
c.printClassName(3);
c.printClassName(3.0);
c.printClassName(3.3f);
c.printClassName("Hello");
c.printClassName((Integer)3);
/*
java.lang.Long
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.String
java.lang.Integer
*/
}
}
泛型编程中还可以配合使用?通配符,使得编程更为简洁
class GeneralType <Type>{
Type obj;
public GeneralType(Type obj){this.obj = obj;}
public Type getObj(){
return obj;
}
}
class ShowType{
public void show(GeneralType<?> o){
System.out.println(o.getObj().getClass().getName());
}
}
public class Test {
public static void main(String[] args){
ShowType st = new ShowType();
GeneralType<Integer> t = new GeneralType<Integer>(2);
GeneralType<Double> d = new GeneralType<Double>(4.3d);
st.show(t); //java.lang.Integer
st.show(d); //java.lang.Double
}
}
泛型不是万能的,我们可以对泛型的类型做一些限制,从而限制那些能够正确处理的类型传进来。实现的方法是在Type后面加上extends关键字,后面接类名或者接口名,限制Type继承自某个类名或者时间某个接口。注意这里接口名前面也是用extends而不是implements。
class GeneralType <Type extends Number>{
Type obj;
public GeneralType(Type obj){
this.obj = obj;
}
public Type getObj(){
return obj;
}
}
//这里就限制了传进来的Type必须是Number的子类。