本人为自学Java系列,内容来自于中国大学mooc华东师范大学陈育良教授《Java核心技术》,在此感谢老师!
一:继承
-
面向对象和面向过程编程语言最大的特点就是变量类型的继承,通过extend去继承父类
-
继承能够解决很多类型的重复定义,类别内的对象属性和方法都具有一定的共同点。将共同点提取出来,即形成父类/基类/超类—Parent class/Base class/Super class
-
其他类型则自动生成子类/派生类-----Child class/Derived class
Human类把Man和Woman的height、weight成员属性和eat方法写成一个父类,两个子类就能继承Human,从而节约很多重复定义。
-
子类会继承父类所有的属性和方法,但是不能访问private成员。
-
子类会继承父类的父类所有的属性和方法,但是不能访问private成员
-
单根继承原则:每个类都只能继承一个类,如果不写extends,Java类都默认继承java.lang.object,Objecvt里面默认有clone equlas finalize getcalss hashCode toString等方法
-
同样方法名和参数情况下,本类的方法会比父类的方法优先级更高
父类:
-
public class Base {
-
private int num = 10;
-
public int getNum() {
-
return this.num;
-
}
-
}
子类:
-
public class Derived extends Base{
-
private int num = 20;
-
-
public int getNum() {
-
return this.num;
-
}
-
-
public static void main(String[] args) {
-
Derived foo = new Derived();
-
System.out.println(foo.getNum());
-
}
-
}
程序返回值为20。子程序会选择本类的方法进行执行。
解释下上章节的继承函数
-
public class A {
-
public A() {
-
System.out.println("11111");
-
}
-
public A(int a) {
-
System.out.println("22222");
-
}
-
}
-
public class B extends A {
-
public B() {
-
//super();
-
System.out.println("333333");
-
}
-
public B(int b) {
-
//super(b);
-
System.out.println("444444");
-
}
-
public static void main(String[] args) {
-
// TODO Auto-generated method stub
-
B obj = new B();
-
System.out.println("==========");
-
B obj1 = new B(10);
-
}
-
-
}
输出结果:
-
11111
-
333333
-
==========
-
11111
-
444444
两个构造器都会默认调用父类的无参构造函数,输入11111.
当我们在每个构造器前面加上super函数,而且super语句必须放在第一条。
当去掉第二行super(b)注释,输出值:
-
11111
-
333333
-
==========
-
22222
-
444444
二:抽象类
抽象类:属性+方法组成,完整的类所有的方法都有实现(方法体),一个完整的类才可以被实例化,如果一个类暂时没有方法实现,就定义为抽象类,抽象类是无法被实例化的。
-
抽象类关键字abstract声明;
-
抽象类的组成
--optional 成员变量,个数不限
--optional具体方法,方式有实现,个数不限
-- optional 抽象方法,加abstract关键字,个数不限
同时对于抽象类我们还要遵循以下的规则
-
抽象类也是类,同样要满足单根继承原则。一个类只能继承一个抽象类
-
完整类要继承抽象类必须实现其所有的方法,否则只能定义为抽象类
抽象类:
-
public abstract class Shape {
-
int area;
-
public abstract void calArea();
-
-
}
完整类继承于抽象类,并实现抽象类中的方法体。
-
public class Rectangle extends Shape {
-
int width;
-
int length;
-
public void set(int length, int width) {
-
this.width = width;
-
this.length = length;
-
}
-
public void calArea() {
-
System.out.println(this.length *this.width);
-
}
-
public static void main(String[] args) {
-
// TODO Auto-generated method stub
-
Rectangle obj = new Rectangle();
-
obj.set(10,5);
-
obj.calArea();
-
}
-
-
}
三:接口
-
紧接继承的定义,如果类的所有方法都没有实现,那么这个类就是接口interface。类只可以继承-extends一个类,但是可以实现-implements多个接口,继承和实现可以同时进行
-
类可以继承多个接口,没有实现的方法将会叠加,即A继承与B C两个接口,B C两个接口所有方法体将会叠加,如果类没有实现接口所有方法,只能定义为抽象类
-
接口里可以定义变量,但是一般是常量,详情可以参考final节
这里给大家写几个简单的例子来描述: 类-抽象类-接口之间的关系
定义三个接口:
-
public interface Aninmal {
-
public void eat();
-
public void move();
-
}
接口2:
-
public interface ClassTree {
-
public void climb();
-
}
接口3
-
public interface CatFamliy extends ClassTree, Aninmal {
-
// 继承多个接口相当于将没有实现的方法全部叠加
-
// eat()
-
// move()
-
//climb()
-
}
Cat类是实现与Animanl接口的,必须实现它所有的方法体
-
public class Cat implements Aninmal {
-
public void eat() {
-
System.out.println("Cat can eat");
-
}
-
public void move() {
-
System.out.println("Cat can move");
-
}
-
}
类LandAnimal由于只实现Animal中的move方法,没有实现eat方法,定义为abstract类
-
public abstract class LandAnimal implements Aninmal {
-
public void move() {
-
System.out.println("LandAnimal cat move");
-
-
}
-
//public abstract void eat();
-
}
Rabbit类是先继承LandAnimal抽象类再实现ClassTree接口
-
public class Rabbit extends LandAnimal implements ClassTree {
-
// 必须先继承再实现
-
public void eat() {
-
System.out.println("Rabbit cat eat");
-
}
-
public void climb () {
-
System.out.println("Rabbit can climb");
-
}
-
}
Tiger类是实现CatFamily接口,所以要实现这个接口所有方法
-
public class Tiger implements CatFamliy {
-
public void move() {
-
System.out.println("Tiger can move");
-
}
-
public void eat() {
-
System.out.println("Tiger can move");
-
}
-
public void climb() {
-
System.out.println("Tiger can move");
-
}
-
}
四:转型
-
基本类型转型
-
变量支持相互转化。比如 int a = (int)3.5 这里进行变量的强转换
基本类型转换:
从高精度往低精度转化,会损失信息,称为收缩变换。这种情况我们需要声明类型转化
从低精度往高精度转化,不损失信息,称为宽松变换。这种情况Java会自动转化。
-
public class Test{
-
public static void main(String[] args) {
-
int a;
-
a = (int)3.5; // 收缩变换
-
System.out.println(a);
-
double b = 3; // 宽松变换
-
System.out.println(b);
-
}
结果:
-
3
-
3.0
-
-
类转型
类型之间可以互相转型,但是只限制于有继承关系的类
---子类可以转化为父类,但是父类不能转化为子类。因为子类有更多的方法和变量
---子类继承父类所有的财产,子类转化为父类(从大到小,即向上转型);从父类直接变成子类(从小变大,即向下转型)
-
public class Man extends Human {
-
public void eat() {
-
System.out.println("i cat eat more");
-
}
-
public void plough() {
-
-
}
-
public static void main(String[] arsg) {
-
Man obj1 = new Man();
-
obj1.eat();
-
Human obj2 = new Man();// upcast向上转换
-
obj2.eat();
-
Man obj3 = (Man)obj2;
-
obj3.eat();
-
// Man obj3 = new Human(); Human是父类,Man拥有父类不具有的成员变量与方法。
-
// 所以Human对象内存无法转型为Man类
-
}
-
}
父类:
package service;
public class Human {
int height;
int weight;
public void eat() {
System.out.println("I cat eat");
}
}
输出结果:
i cat eat more
i cat eat more
i cat eat more
如上序程序就有类转型,Man类转为Human类,即衍生类引用转为基类引用。类型转换的作用就是带来多态。
程序中有一个eat方法,和父类中的eat方法方法名和参数一致,我们把这个称为方法重写。(不同于重载,重载是方法名一致但是形参类型或者个数不一致)。且子类方法的优先级高于父类。
五:多态
多态拥有三个必要条件:
-
继承 extends
-
重写 overwrite
-
父类引用指向子类对象 Father obj = new Son()
当我们使用多态调用方法时,对象会检查父类是否有此方法,如果没有就会编译错误。如果有的话,就会调用子类同名方法。
多态的作用到底有什么呢:
-
以统一的接口来操纵某一类中不同对象的动态行为
-
对象之间的解耦
-
代码实例:
public interface Aninmal {
public void eat();
public void move();
}
public class Dog implements Aninmal {
public void eat() {
System.out.println("Dog can eat");
}
public void move() {
System.out.println("Dog can move");
}
}
public class Cat implements Aninmal {
public void eat() {
System.out.println("Cat can eat");
}
public void move() {
System.out.println("Cat can move");
}
}
-
public class AnimalTest {
-
public static void haveLunch(Aninmal a) {
-
a.eat();
-
}
-
Aninmal a;
-
AnimalTest c = new AnimalTest();
-
public static void main(String[] args) {
-
haveLunch(new Cat()); // 此处等于转型 Aninaml a = new Cat(); haveLunch(a)
-
haveLunch(new Dog());
-
haveLunch(new Aninmal() {
-
-
@Override
-
public void move() {
-
// TODO Auto-generated method stub
-
System.out.println("move Test");
-
}
-
-
@Override
-
public void eat() {
-
// TODO Auto-generated method stub
-
System.out.println(" eat Test");
-
}
-
});
-
}
-
}
输出结果:
-
Cat can eat
-
Dog can eat
-
eat Test
我们通过Animal接口,完成对于Dog和class两个不同对象的自己各自独有的行为。第三个是匿名类,重写补全Animal接口的方法,调用补全的方法。
我们haveLunch方法形参可以传入不同对象,这个称为对象的解耦。
六:契约设计
契约:通过接口定义了方法的名称,参数和返回值。规范了派生类的行为
基于接口,利用转型和多态,不影响真正方法调用,成功地将调用类和被调用类解耦。
-
被调用类:
-
调用类:
两个方法之间已经解耦设计,havelunch已经定义其方法名 参数名和方法体,调用类可以利用多态的功能实现多个对象的不同行为方法。