一、继承、封装、多态三大特征。
继承:extends意思是扩展,子类拥有父类的一切,子类是父类的扩展。
我们先来写一个类:
class Person
{
String name;
int height;
public void rest()
{
System.out.println("learning java");
}
}
再写另外一个类:
class Student
{
String name;
int height;
String major;
public void study()
{
System.out.println("learning");
}
public void rest()
{
System.out.println("learning java");
}
}//发现student里面重复了person的属性和方法
这种时候student就没必要这样写,而选择用继承:
class Student extends Person
{
String major;
public void study()
{
System.out.println("learning java");
}
}
采用下面的继承,在实例化一个student对象的时候,可以发现已经拥有了person的属性:
继承使用要点:
* 父类也称作超类、基类、派生类;
* java里面只有一个直接父类,没有像C++那样的多继承,多继承会引起混乱,使得继承过于复杂,系统难以维护;
* java中类没有多继承,接口有多继承;
* 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问(比如父类私有的属性和方法);
* 如果定义一个类时没有调用extends,则它的父类是:java.lang.Object;
(可以用ctrl + T 查看类的继承层次结构)
instanceof运算符:
instanceof用来判断某个对象是不是某个类型
System.out.println(stu instanceof Student);
System.out.println(stu instanceof Person);
二、方法的重写(override):
父类的某个方法的实现不完全符合子类的要求,因此可以进行改变,变成独特的实现,也就是override;
class Vehicle
{
public void run()
{
System.out.println("running……");
}
public void stop()
{
System.out.println("stop");
}
public Person whoIsPassenger()
{
return new Person();//返回的类型是一个person类
}//父类里面的返回乘客方法
}
class horse extends Vehicle
{
public void run()
{
System.out.println("didadidadida");
}//重写了run方法
public Student whoIsPassenger()
{
return new Student("john",178,"java");
}//重写父类的返回乘客方法,返回值类型小于父类的返回值,因为返回的student类时person类的子类
}
总结方法的重写需要符合下面的三个要点:
* “==”:方法名,形参列表相同;
* “<=”:返回值和声明异常类型,子类的必须要小于等于父类的;
* “>=”:访问权限,子类大于等于父类。
Object类是所有java类的根基类,也就是所有的java对象都拥有object类的属性和方法。如果在类的声明里没有extends关键字声明其父类,那么默认是继承的object类。Object类属于java的lang包里。
object类里的toString()方法
public class testObject {
public static void main(String[] args)
{
//Object obj;
testObject to=new testObject();
System.out.println(to.toString());
}
}
返回了类的路径和十六进制的数字组成的字符串:
可以重写tostring方法
public class testObject {
public static void main(String[] args)
{
//Object obj;
testObject to=new testObject();
System.out.println(to.toString());//toString方法返回一个十六进制的字符串
}
public String toString() {
return "override toString";
}
}
运行结果就变成了:
==和equals方法的重写
“==”是比较双方是否相同,如果是基本类型则是表示值相等,如果是引用类型,就是比较指向地址是否相等,也就是是否指向同一个对象;
Object类中定义有一个方法:public boolean equals(Object obj)方法,提供定义“对象的内容是否相等”的逻辑。
equals是经常被重写的方法(比如公安系统,那么只要两个人的身份证号相等那么就认为是同一个人,对象的其他内容就不需要再比较)
可以查看equals的源码:
例如定义一个user类:
class User{
int id;
String name;
String pwd;
//按住alt shift + s,可以选择自动生成constructor
public User(int id, String name, String pwd) {
super();
this.id = id;
this.name = name;
this.pwd = pwd;
}
}
用“==”和“equals方法”
User u1=new User(1000,"john","123456");
User u2=new User(1000,"archie","123456");
System.out.println(u1==u2);
System.out.println(u1.equals(u2));
由于这是两个对象,所以返回了false;
我们可以对equals方法重写,可以使用eclipse自动生成的hashcode和equals方法,也可以自己写:
这里改为只判断id一个属性的值是否相等
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;//先大范围判断整个类,地址一样肯定一样
if (obj == null)
return false;//如果有一个为空那肯定不一样
if (getClass() != obj.getClass())
return false;//如果类的类型不一样
User other = (User) obj;//这里需要一个强制类型的转换
if (id != other.id)
return false;//只判断id一个属性的值
return true;
}
这次的运行结果变成了:
也就是判断了id属性是一样的值。
我们阅读String类的源代码,可以发现它也重写了equals方法:
进行简单的测试:
String str=new String("yanhaoqi");
String str2=new String("yanhaoqi");
System.out.println(str==str2);//false因为这是两个对象
System.out.println(str.equals(str2));//true因为内容一样
super关键字
super是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性。
来看一个例子,先写父类:
class fatherClass{
public int value;
public void f() {
value=100;
System.out.println("fatherClass value is :"+value);
} }
然后在子类里重写父类的方法,但是依然用super来访问父类中的方法和属性:
class childClass extends fatherClass{
public int value;
@Override
//重写父类的方法f
public void f() {
// TODO Auto-generated method stub
value=200;
super.f();//访问父类对象的普通方法
System.out.println("childClass value is :"+value);
System.out.println(value);
System.out.println("fatherClass value is :"+super.value);//调用父类对象的成员变量
}
}
在main函数中调用看看:
public static void main(String[] args) {
fatherClass f=new fatherClass();
childClass c=new childClass();
f.f();
c.f();
}
结果是这样的:
一般来说构造器里的第一行没有显示调用super()的话或者this(),那么java都会默认调用super(),含义是调用父类的无参数构造方法,这里的super()可以省略(可以看到我上面的自动生成构造器的代码里就有一行super())
三、继承树追溯问题:
我们还是先来写一个父类和子类:
class father{
public father() {
System.out.println("building father class");
}
}
class child extends father{
public child() {
System.out.println("building child class");
}
}
在main方法里new一个子类看看:
public static void main(String[] args) {
System.out.println(“building a child class”);
child c=new child();
}
发现输出结果意外的是这样:
也就是说,在创建子类的时候已经调用了父类的方法,这丫就是上面所说的:
“构造器里的第一行没有显示调用super()的话或者this(),那么java都会默认调用super()”
因此这里面的过程在构造child类的时候首先第一句默认的super()会去调用father类的构造器,然后father类里面也有默认的super(),回去调用父类object的构造器,然后再一步一步返回回来到child;
这个追溯的过程有点类似前面的static静态初始化块的过程。