1、extends和final
java的类中没有多重继承,只有多层继承。java中所有的类都是从java.lang.Object直接或间接派生,所以类都具有其方法。使用extends来从指定类继承,如果不想类当做父类即不能派生其它类,可以使用final来声明这个类(String、System都是final类型):
class Base{}
final class sub extends Base{}
2、override
java中子类重写(覆盖)父类方法时,子类方法的返回值类型应该与父类方法相等或更小,子类方法抛出的异常类也是应与父类方法相等或更小。使用super来调用父类中被覆盖的方法,跟this一样,super也不能出现在静态方法中,因为它是通过一个对象而不是类来调用的:
class Base
{
public int num;
public void func()
{
System.out.println("Base func");
}
}
class Sub extends Base
{
public int num = 10;
public void func()
{
System.out.println("Sub func");
}
public void test()
{
int i = num; //使用子类的num
int j = super.num; //使用父类的num
func(); //调用子类的func
super.func(); //调用父类的func
}
}
子类重写父类的成员变量时,相当于隐藏了父类中的成员变量:
class Parent
{
public String tag = "Parent";
}
class Child extends Parent
{
private String tag = "Child";
}
public class Test
{
public static void main(String[] args)
{
Child d = new Child();
//String s = d.tag; //错误,父类中tag被隐藏
String str = ((Parent)d).tag; //强制转换后可以访问tag
}
}
3、初始化块
使用{}来定义初始化块,初始化块在构造函数之前执行,初始化块与成员变量初始化的执行先后顺序为代码的先后顺序,且如果初始化块在成员变量初始化之前的话,初始化块内只能对该成员变量进行初始化,不能引用该成员变量。static{}用来定义静态初始化,其类似于静态成员函数,不属于某个对象而属于整个类,所以其执行顺在普通初始化块之前:
public class Test
{
{
//第二执行
num = 10;
//System.out.println(num); //错误,不可以引用num
}
public int num = 20; //第三执行
{
//第四执行
num = 30;
System.out.println(num); //可以引用num
}
public Test()
{
//最后执行
System.out.println("Test");
}
static
{
//最先执行
System.out.println("dd");
}
public static void main(String[] args)
{
Test t = new Test();
}
}
4、构造函数
java类中也存在一个不带任何参数的默认构造函数,当自定义了构造函数后就不再调用它。类的对象在内存分配后会自动进行成员变量的初始化,初始化规则与数组自动初始化规则相同,即数值类元素初始化为0、boolean类型为false、引用类型为null。子类中通过super来调用父类的构造函数,完成父类的初始化:
class Parent
{
public String name;
public double size;
public Parent(String name, double size)
{
this.name = name;
this.size = size;
}
}
class Child extends Parent
{
public String color;
public Child(String name, double size, String color)
{
super(name, size);
this.color = color;
}
public static void main(String[] args)
{
Child c = new Child("测试", 5.6, "红色");
}
}
java中构造函数可以调用另一个构造函数,通过this:
public class Apple
{
public String name;
public String color;
public double weight;
public Apple(String name, String color)
{
this.name = name;
this.color = color;
}
public Apple(String name, String color, double weight)
{
this(name, color);
this.weight = weight;
}
}
5、父类子类的转换
子类对象可以赋值给父类引用变量;父类对象不能赋值给子类引用变量;父类引用可以强制转换为子类引用,此时父类引用必须实际指向的是一个子类对象,如:
Object obj = "test"; //子类String对象赋值给父类Object引用变量
String s = new Object(); //子类引用不能指向父类对象
String str = (String)obj; //可以将obj强转为String对象,因为对象obj实际上是一个String类型
在强制转换之前可以使用instanceof运算符来判断这个对象是否是指定类型或其子类或其实现类:
Object obj = "test";
if(obj instanceof String)
{
String str = (String)obj;
System.out.println("df");
}
6、多态
class Base
{
public int id = 0;
public void func()
{
System.out.println("Base func");
}
}
class Sub extends Base
{
public int id = 1;
public void func()
{
System.out.println("Sub func");
}
public void test(){}
public static void main(String[] args)
{
Base b; //b编译时类型为父类Base
b = new Sub(); //允许将子类对象赋给父类引用变量
b.func(); //输出为"Sub func",即b运行时类型为子类Sub,是多态的表现
int i = b.id; //i为0,成员变量不具备多态性
//b.test(); //错误,不能调用非重写函数
((Sub)b).test(); //强制类型转换后可以调用非重写函数,Base父类对象b实际上是一个Sub子类对象,所以可以强制类型转换
}
}