第三章  Java-C++(下)


             --
继承



第一节 继承

1.何为继承?What is Inheritance?



在上图中,(视频下载) (全部书籍)对于车来讲,汽车就是子类。对于汽车来讲,奔驰就是子类。车是汽车的基类,超类,或说父类。到底什么是继承?马克-to-win,子类把父类的方法和属性当成自己的一样随便用的这种现象叫继承。In OOP, the ability that subclass inherits all of the variables and methods defined in the superclass is known as Inheritance.

继承是一种“是”的关系,比如汽车是一种车,奔驰是一种汽车。(It represent is-a relationship)
Syntax(语法)
class SubClassName extends SuperClassName{

}


被继承的类叫超类(superclass)。
继承超类的类叫子类(subclass)。
子类继承了超类定义的所有实例变量和方法包括静态的变量和方法(马克-to-win见下例),(视频下载) (全部书籍)并且为它自己增添了独特的元素。子类只能有一个超类。Java不支持多超类的继承。

子类拥有超类的所有成员,但它不能直接访问超类中被声明成private的成员。马克-to-win:儿子能拿父亲保险箱中的东西吗?为什么要放保险箱?

例1.1---本章源码

class A1Mark {
    static int si=5;//静态的属性和方法一样属于子类,用子类或父类类名都可以调用静态变量或方法
    int i; // 同一个包内,public by default
    private int j; // private to A
    int getJ() {
        return j;
    }
    static int getSi(){
        return si;
    }
    void setij(int x, int y) {
        i = x;
        j = y;
    }
}
// A1Mark's j is not accessible here.
class B1 extends A1Mark {
    static int sbi=6;//子类可以正常有静态变量
    int total;
    void sum() {
        // total = i + j; // ERROR, j is not accessible here
        total = i + si+getJ()+getSi(); // no problem , i can be used here.
    }
/*子类的静态方法甚至可以覆盖父类的静态方法。*/  
    static int getSi(){
        return si*10;
    }
}
public class Test {
    public static void main(String args[]) {
        B1 subOb = new B1();
        subOb.setij(10, 12);//可以直接用基类的方法
        System.out.println(subOb.i+" "+B1.sbi+" "+subOb.si+" "+subOb.getSi()+" "+B1.si+" "+B1.getSi()+" "+A1Mark.si+" "+A1Mark.getSi());
        subOb.sum();
        System.out.println("Total is " + subOb.total);
    }
}

 

result is:

10 6 5 50 5 50 5 5
Total is 77


2.继承的访问控制: (视频下载) (全部书籍)

(比如一个类中的protected成员对于“不同的包中的非子类”是不可见的。



说明:1.任何public的内容可以被从任何地方访问。 2.private的成员不能被该类外看到。 3.如果一个成员不含有一个明确的访问说明,马克-to-win,它只对同包可见, 不同包不可见。这是默认访问。 4.protected是同包都可见,且子类都可见。又不同包同时又不是子类,就不可见。

以下就上表中的一些难于理解的知识点给出实例进行分析:

2.1 以下例子说明:1)子类可以访问protected 2)同一包中非子类(Test)可以访问protected。

例1.2.1---本章源码

class AMark {
    protected int i;
    protected void printI() {
        System.out.println("i=" + i);
    }
}

class B extends AMark {
    public void printIInB() {
        System.out.println("in B i=" + i);//子类可以访问protected
    }
}

public class Test {
    public static void main(String[] args) {
        AMark a=new AMark();
        a.i=7;//protected是同一包中对非子类(Test)可见,
        a.printI();
        B b = new B();
        b.i = 10;//protected是同一包中对非子类(Test)可见,马 克 -t o-w i n
        b.printI();
        b.printIInB();
    }
}

result is:
i=7
i=10
in B i=10



2.2 以下例子说明:protected是不同包中对子类可见,对非子类不可见。  (视频下载) (全部书籍)

例1.2.2.a:---本例为正常用法。

package p1;
public class A {
    protected int i;
    protected void printIProtected() {
        System.out.println("i=" + i);
    }
}


package p2;
import p1.A;
class B extends A {
    void printIInB() {
        System.out.println("in B i=" + i);//protected是不同包中对子类(Test)可见,马 克-t o-w i n
        printIProtected();
    }
}

public class Test  {
    public static void main(String[] args) {
        A a=new A();
   //     a.i=7;//报错, 注意这里不能直接用
 //       a.printIProtected();//报错, 注意这里不能直接用
        B b = new B();
 //     b.i = 10;//报错,Test不是A子类,非子类不能访问protected
 //     b.printIProtected();//报错,Test不是A子类,非子类不能访问protected
        b.printIInB();
    }
}


结果:
in B i=0
i=0


例1.2.2.b:---本例为非正常用法,通常不直接访问protected方法。比如b.printIProtected();


package p1;
public class A {
    protected int i;
    protected void printIProtected() {
        System.out.println("i=" + i);
    }
}

package p2;
import p1.A;
public class Test extends A {
    void printIInB() {
        System.out.println("in B i=" + i);//protected是不同包中对子类(Test)可见,马 克-t o-w i n
        printIProtected();
    }
    public static void main(String[] args) {
        Test b = new Test();
        b.i = 10;//protected是不同包中对子类(Test)可见,
        b.printIProtected();//protected是不同包中对子类(Test)可见,
        b.printIInB();
    }

}


运行结果:

i=10
in B i=10
i=10

2.3 以下例子说明: public, private,protected的用法。

例1.2.3---本章源码

class A {
    protected int i;
    public int ipub;
    private int ipri;//私有变量, 子类访问不到。
    public void printI_to_win() {
        System.out.println("i=" + i);
    }
}

class B extends A {
    public void BprintI() {
        System.out.println("i= in B " + i);//子类可以访问protected
        // ipri=9; //error, can not access访问
        ipub = 9;
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.i = 10;//同一包中其他类(Test)可以访问protected
        b.ipub = 8;
        b.printI_to_win();
        b.BprintI();
    }
}

 

result is:

i=10
i= in B 10





3."超"关键字(super keyword) (视频下载) (全部书籍)
马克-to-win,Super是一个参考(或说指针)指向他紧邻的父类(见下面的例子)。
用super可以指向被隐藏的父类的同名成员。



3.1 super指向父类的成员

注意: 下例中:子类和父类都有i,我们一共有两个i,用super可以指向前一个父类的i。 

例1.3.1---本章源码

class AMark_to_win {
    int i;
}

class B extends AMark_to_win {
    int i;

    public B(int x, int y) {
        super.i = x;//AMark_to_win 的 i被赋值
        i = y;//B的i被赋值
    }

    public void show() {
        System.out.println("i in superclass: " + super.i);
        System.out.println("i in subclass: " + i);
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B(2, 3);
        b.show();
    }
}

result is:
i in superclass: 2
i in subclass: 3

3.2 当有两次继承时,演示super指向他紧邻的父类  (视频下载) (全部书籍)

我们把上面的例子扩展成两次继承, 就看出:马克-to-win,Super是一个参考(或说指针)指向他紧邻的父类,而不是最底层的基类。

例1.3.2---本章源码

class ZMark_to_win {
    int i;
    void show() {

System.out.println("i in ZMark_to_win: " + i);
    }
}
class A extends ZMark_to_win {  
    int i;
    void show() {
        super.show();
        System.out.println("i in A: " + i);
    }
}

class B extends A {
    int i;
    public B(int x, int y) {
        super.i = x;   
        i = y;
    }
    public void show() {
        super.show();
        System.out.println("i in B: " + i);
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B(2, 3);
        b.show();
    }
}

结果是:

i in ZMark_to_win: 0
i in A: 2
i in B: 3

   

4.隐藏  (视频下载) (全部书籍)

技术核心和实例前面已经给出,这里只是给出大家对这种现象的一个定义而已,马克-to-win:子类重新定义一个与父类那里继承来的域变量完全相同的变量,称为域的隐藏。
这里所谓隐藏是指子类拥有了两个相同名字的变量,一个继承自父类,另一个由自己定义。相当于把父类的变量“隐藏”起来了。

但子类的方法可以通过super操作父类的成员变量。

下面的例子当中,就分新卡和老卡,this获取新卡的余额,super获取老卡的余额。

例1.4.1---本章源码


class HealthCardM_t_w {
    double balance = 90;
    double getBalance() {
        return this.balance;
    }
}

class New_Card extends HealthCardM_t_w {
    double balance; // 隐藏父类的balance
    public New_Card(int in) {
        balance = in;
    }
    double getOldBalanceInNew_Card() {
        return super.balance;
    }
    double getOldBalanceByMythodInNew_Card() {
        return super.getBalance();
    }
    double getThisBalanceInNew_Cardget() {
        return this.balance;
    }
}

public class Test {
    public static void main(String args[]) {
        New_Card myNewCard = new New_Card(500);
/* 对象myNewCard有两个balance变量,一个继承自父类,另一个是自定义的。*/
        System.out.println("马克-to-win " + myNewCard.getThisBalanceInNew_Cardget());
        System.out.println("马克-to-win " + myNewCard.getOldBalanceInNew_Card());
        System.out.println("马克-to-win " + myNewCard.getOldBalanceByMythodInNew_Card());
        System.out.println("马克-to-win " + myNewCard.getBalance());

    }
}

result is :

马克-to-win 500.0
马克-to-win 90.0
马克-to-win 90.0
马克-to-win 90.0



5.覆盖(Override)  (视频下载) (全部书籍)

马克-to-win:方法的覆盖(Override)是指子类重写从父类继承来的一个同名方法(参数、返回值也同)。

例1.5.1---本章源码

class AAAMark_to_win {
    double f(double x, double y) {
        return x * y;
    }
}

class BBB extends AAAMark_to_win {
    double f(double x, double yMark_to_win)
/*注意这里的返回值必须为double,如返回int值,
我试过报错,因为sun公司不出这个语法,他没法办,
到时obj.f(4,6)不知道调用基类还是本类的方法。
*/
    {
        return x + yMark_to_win;
    }
}

public class Test {
    public static void main(String args[]) {
        AAAMark_to_win a = new AAAMark_to_win();
        System.out.println(a.f(4, 6));
        BBB obj = new BBB();
        System.out.println(obj.f(4, 6));
    }
}

result is:
24.0
10.0

例1.5.2---本章源码 

class AAAMark_to_win {
    double f(double x, double yMark_to_win) {
        return x * yMark_to_win;
    }
}

class BBB extends AAAMark_to_win {
    double f(double x, double y) {
        return x + y;
    }
}

public class Test {
    public static void main(String args[]) {
        AAAMark_to_win a = new AAAMark_to_win();
        System.out.println(a.f(4, 6));
        BBB obj = new BBB();
        System.out.println(obj.f(4, 6));
/* 基类指针指向子类或说派生类效果就像子类指针指是一样的,为什么?马克-to-win:因为new BBB();时,BBB的属性的内存空间也被开辟了。只是语法上允许“基类指针指向派生类”
*/      
        AAAMark_to_win obj1 = new BBB();
        System.out.println(obj1.f(4, 6));
    }

}

结果是: 

24.0
10.0
10.0

例1.5.2.a:本例编译报错:overide时, 子类的方法的visibility不能更小,起码要大或相等。
class AAAMark_to_win {
    public double f(double x, double yMark_to_win) {
        return x * yMark_to_win;
    }
}

class BBB extends AAAMark_to_win {
    double f(double x, double y) {
        return x + y;
    }
}

public class Test {
    public static void main(String args[]) {
        AAAMark_to_win a = new AAAMark_to_win();
        System.out.println(a.f(4, 6));
        BBB obj = new BBB();
        System.out.println(obj.f(4, 6));
/* 基类指针指向子类或说派生类效果就像子类指针指是一样的,为什么?马克-to-win:因为new BBB();时,BBB的属性的内存空间也被开辟了。只是语法上允许“基类指针指向派生类”
*/     
        AAAMark_to_win obj1 = new BBB();
        System.out.println(obj1.f(4, 6));
    }

}

Override,Overload,Overwrite的区别【新手可忽略不影响继续学习】  (视频下载) (全部书籍)

方法的覆盖(Override)是指子类重写从父类继承来的一个同名方法(参数、返回值也同),马克-to-win:此时子类将 清除父类方法的影响,实现自身的行为。实在想用原来的,可以用super。顺便说,overload指同名方法,通过不同的参数样式共存, 有时用这个, 有时用那个。参数样式指,不同的参数类型,不同的参数个数,不同的参数顺序,返回值不起作用。再顺便说,比较权威公开的著作,都支持overwrite在java中不 存在的说法。我们看看下面的一个实用的例子。此例子证明,compiler(编译器)一定是按照先子类,后父类,先精确匹配,后模糊匹配的顺序。

例1.5.3---本章源码

class AAAMark_to_win {
    double f(double x, double yMark_to_win) {
        return x * yMark_to_win;
    }
    double f(int x, double y) {
        return x * y*2;
    }
}
class BBB extends AAAMark_to_win {
    double f(double x, double y)
    {
        return x + y;
    }
}
public class Test {
    public static void main(String args[]) {
        BBB obj = new BBB();
/*找参数的准确匹配, 子类中没有, 就去父类中找*/        
        System.out.println(obj.f(4, 6.0));
/*如果没有准确匹配, 就模糊匹配(强转一下),马克-to-win:还是按照从子类到父类的顺序*/        
        System.out.println(obj.f(4.0, 6));
    }
}

结果是:

48.0
10.0






6.继承当中的构造函数规则  (视频下载) (全部书籍)

马克-to-win:继承当中的构造函数规则貌似复杂: 记住我给你的以下几条口诀, 你高枕无忧。1)如果你在某类中写了带参构造函数,系统就不会再为你在那类中自动添加无参构造函数了。2)如你没有写无参构造函数,且机器也不会为你自动添加这个无参构造函 数时(因为你已经有带参构造函数了),你不可以主动调无参构造函数。3)子类的构造函数中不能人为的写两个super。4)构造函数中要是你人工想写super,super必须为第一句话。构造函数中要是你不写super,机器会为你加无参数super().马克-to-win:5)既然super必须为第一句话,创建子类对象时,构造函数调用次序为,先最低的超类直到最高的子类。


例1.6.1---本章源码 

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside AAAMark_to_win's constructor.");
    }
    AAAMark_to_win(int j) {
        System.out.println(j);
    }
}
class BBB extends AAAMark_to_win {
    BBB() {
        super(3);
        System.out.println("Inside BBB's constructor.");
    }
    BBB(int i) {
        System.out.println(i);
    }
}
class C extends BBB {
    C(int a) {
/*马克-to-win: super必须是第一句话,彻底不写也行。因为机器会为你自动加。
super must be the first statement. without it, also ok.the result
is exactly the same as right now, because machine will add automatically for you. but if you have it, it must be the first statement.
*/     
//        super();//注意这上下两句,只能保留一个
        super(1);
        System.out.println("Inside C's constructor.");
    }
}

public class Test {
    public static void main(String args[]) {
/*马克-to-win: 这里你不能写成C(),即使不谈继承,也一样。因为你已经有C(int a) {} ,系统不会为你自动添加C() {} 。
 
here you can not write as new C(); even without inheritance,still, you can not write as new C(); because if you have C(int a) {} already, machine will not automatically add C() {} for you.*/
        C c = new C(5);
    }
}

result:

Inside AAAMark_to_win's constructor.
1
Inside C's constructor.


例1.6.2---本章源码

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside AAAMark_to_win's constructor.");
    }
}
class BBB extends AAAMark_to_win {
    BBB(double g) {
        System.out.println("Inside BBB's constructor.");
    }
}
class C extends BBB {
    C(int a) {
/* 马克-to-win: 假如你没有下列的super(5.9),系统将报错,因为你没有BBB(){}, 系统也不会自动替你加。if you don't have the following super(5.9), it will report error, because you don't have BBB(){}.*/
        super(5.9);
        System.out.println("Inside C's constructor1.");
    }
}
public class Test {

public static void main(String args[]) {
        C c = new C(5);
    }
}

 

result is:

Inside AAAMark_to_win's constructor.
Inside BBB's constructor.
Inside C's constructor1.

例1.6.2-b:

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside AAAMark_to_win's constructor.");
    }
    AAAMark_to_win(int j) {
        System.out.println(j);
    }
}
class BBB extends AAAMark_to_win {


}
class C extends BBB {
    C(int a) {
/*马克-to-win: super必须是第一句话,彻底不写也行。因为机器会为你自动加。
super must be the first statement. without it, also ok.the result
is exactly the same as right now, because machine will add automatically for you. but if you have it, it must be the first statement.
*/    
    //    super();//注意这上下两句,只能保留一个
        //    super(1);
        System.out.println("Inside C's constructor.");
    }
}

public class Test {
    public static void main(String args[]) {
/*马克-to-win: 这里你不能写成C(),即使不谈继承,也一样。因为你已经有C(int a) {} ,系统不会为你自动添加C() {} 。
 
here you can not write as new C(); even without inheritance,still, you can not write as new C(); because if you have C(int a) {} already, machine will not automatically add C() {} for you.*/
        C c = new C(5);
    }
}


结果:
Inside AAAMark_to_win's constructor.
Inside C's constructor.

例1.6.3---本章源码

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside A's constructor.");
    }
}
class BBB extends AAAMark_to_win {
    BBB() {
        System.out.println("Inside BBB's constructor.");
    }
}
class C extends BBB {
/* 马克-to-win: 无论C()整个comment out,还是把C()里面的内容都去掉,我试过,效果是一样的,AAAMark_to_win和BBB的构造函数都会被调用。 AAAMark_to_win' constructor and BBB's constructor still are called, */
    C() {
        System.out.println("Inside C's constructor.");
    }
}
public class Test {
    public static void main(String args[]) {
        C c = new C();
    }
}

result is:

Inside A's constructor.
Inside BCC's constructor.
Inside C's constructor.


  

7.何为抽象方法和抽象类? (视频下载) (全部书籍)

马 克 -to -win:方法前有个abstract修饰符,就叫抽象方法。类前有个abstract修饰符就是抽象类,完了,简单就好记。

以下是二者的要点:马 克 -to -w in :
1)抽象方法没有函数体。有童鞋说,这有什么意义呢?比如下面的例子,当我们不知道现在是什么车时,你让我写驾驶(steer)这个方法,我怎么写呢?这种场合就需要抽象方法。
2)抽象类(Veh)的子类(Lim)只要不是抽象类,
马克-to-win:它自己(Lim)或它的父类(Car)必须把那个抽象类里的抽象方法全部实现掉。这句话很复杂,对照下面的例子来理解。
3)抽象类不能被实例化。字面上好理解,抽象的东西那么抽象,看不见摸不着,当然不能被实际的具体的生成了。还是举上面的例子。当我们现在连什么车都不知道时,也不知道它是自行车还是豪华轿车时,你让我具体地生成这辆车,当然是不可能了。

4)抽象方法不能为private,final或者static, native, synchrozied为什么?(视频下载) (全部书籍)【新手可忽略不影响继续学习】马克-to-win:抽象方法的最实质的意义在于被未来的子类覆盖实现掉。它自己是个空方法。private的实质意义在于本类其他方法调用它。你自己是个空方法,别人调用你有什么用?所以abstract和private在一起毫无意义。final规定子类不能再覆盖它。abstract是专等着要别人来覆盖,二者矛盾。所以不能放在一起使用。有关static,我们上一章讲过: 马克-to-win:static方法是静态方法,可以直接被类名所调用。而abstract方法是无方法体的方法,直接调用毫无意义,所以矛盾了。顺便说一下,抽象方法也不能为native和synchronized,native说明此方法正在用其他语言(c)编写,此方法是c写的。你java这里却声明说方法是空的,这不符合逻辑。synchronized说明这个方法和另外一个实在做事的方法不能同时执行。而现在你自己却是一个空方法,这也毫无意义。


抽象类和抽象方法有什么用呢?马克-to-win:当初sun公司为什么要设计抽象类和抽象方法呢?当你在做车的系统设计时,(视频下载) (全部书籍)当你设计车这个通用类时,假如你确认别人实例化车这个通用类没有意义时(不知道是bike还是豪华轿车),你就坚决的在车这个通用类的类名前冠以abstract,将来就没人能实例化车这个类了。进一步讲:因为你不知道是什么车?所以你不知道如何驾驶,是拐把?还是方向盘?但你知道不管是什么车都得驾驶。所以你写个驾驶steer方法,冠以abstract,这样后来的子类,必须得把这个抽象方法实现掉。通过这种方法,你做架构设计的人就规定了后人的行为:必须得把驾驶这个抽象方法实现。

抽象类和抽象方法什么关系?抽象类中可能有抽象方法,也可能没有抽象方法。(视频下载) (全部书籍)那位说,就跟没说一样,那抽象类和抽象方法都叫抽象,他们必定有关系,那关系是什么呢?如果一个类中有抽象方法,它必须得是抽象类。

An abstract class may have no abstract method,such as the following class Car. 马  克- t  o --wi n: At this time,the only point and the meaning of abstract class is that we can not instantiated the class, because it is abstract class.Why an abstract class can have a nonabstract method? what is the point? also in logic, think over the following example, car is a bit abstract in that you dont' know exactly whether it is a truck or a jeep or a limersine, 马克-to-win:so it is defined as a abstract class. but no matter whether it is truck,jep, or limersine, it definitely use steering wheel. so its steer() method is an ordinary method instead of an abstract method.  )
Abstract class can’t be instantiated.



例1.7.1---本章源码

abstract class Nothing {//里面有方法也照样声明为abstract

   void nothing() {
       System.out.println("nothing");
    }
}
abstract class VehMark_to_win {
    abstract void steer();
    abstract void move();
}
class Bike extends VehMark_to_win {//Bike不是抽象的, 所以必须得全部实现abstract方法
    void steer() {
        System.out.println("Turn handlebar");
    }
    void move() {//Bike不是抽象的, 所以必须得实现move方法
        System.out.println("move");
    }
}
abstract class Cart extends VehMark_to_win {
    //因为Cart是抽象的, 可以这里还是什么都不干
}
abstract class Car extends VehMark_to_win {
    void steer() {
        System.out.println("Turn steering wheel");
    }
    void move() {
        System.out.println("move");
    }
}
class Lim extends Car {
    //之所以这里可以什么都不干, 而且还不是抽象的,马克-to-win: 因为父类Car全部实现了Veh的抽象方法
}
public class Test {
    public static void main(String[] args) {
        Nothing n0;//声明是没问题的, 但不能实例化
        Bike b = new Bike();
        Lim l = new Lim();
        b.steer();
        l.steer();
    }
}


result is:
Turn handlebar
Turn steering wheel

例1.7.2(抽象类可以继承实体类)---本章源码 (视频下载) (全部书籍)

class VehMark_to_win {
    void steer() {
        System.out.println("Turn steering wheel");
    }
}
abstract class Cart extends VehMark_to_win {
    //因为Cart是抽象的, 可以这里还是什么都不干
}
abstract class Car extends VehMark_to_win {

    void move() {
        System.out.println("move");
    }
}
class Lim extends Car {
    //之所以这里可以什么都不干, 而且还不是抽象的,马克-to-win: 因为父类Car全部实现了Veh的抽象方法
}
public class Test {
    public static void main(String[] args) {
        Lim l = new Lim();
        l.move();
    }
}
输出结果:
move

8.多态Polymorphism,向上转型Upcasting,动态方法调度(dynamic method dispatch) (视频下载) (全部书籍)

什么叫多态?简言之,马 克 - t o - w i n:就是父类引用指向子类时,父类和子类必须同时拥有某个同名函数,父类引用到底指向谁(调用谁的函数),是在runtime时决定的,因此呈现多种状态(不知道会指向若干子类中的哪一个还是父类自己)。拿上一节的例子来讲,比如运行时如果用户输入自行车,就执行自行车的驾驶方法。如果用户输入小轿车,就执行小轿车的驾驶方法, 涉及到用户,这些都只能在运行时才能干。运行时的,就是动态的,所以这也是动态方法调度(dynamic method dispatch), 既然是父类指针指向子类,这也是向上转型Upcasting(为什么是向上?看我本章的第一张图:父类 fuLei=(父类)new 子类(); ,,,,感觉到一种向上转型的意味吗?子类 zilei=(子类)fulei;    这是向下转型)。顺便提一句。马克-to-win:学术界另有一种说法,overload也算多态。我认为这只是学术上的一种说法而已,张三爱这么认为,李四爱那么认为,无所谓对错。不像语法错误,错了,编译器真不让你通过。不过本书作者不支持这种overload说法。

多态有什么用?马 克  -   t   o - w   i  n:(视频下载) (全部书籍)我给大家想了两个需求: 1)要求程序运行起来以后,如果用户输入自行车,就执行自行车的驾驶方法。如果用户输入小轿车,就执行小轿车的驾驶方法。这是就用到父类指针指向子类时的override。2)如果你有一千个子类。要求你依次执行这一千个子类当中的打印。你当然可以一个一个实例化子类后分别执行。马克-to-win:累也累死了,你可以编一个循环。用通用的基类指向所有的派生类。几行程序即可,你可以参照本节的例子。不用这技术, 还真解决不了这问题!

Polymorphism means one type,many form

Dynamic method binding(dynamic method dispatch),方法覆盖仅在两个方法的名称和类型声明都相同时才发生(override)。

动态方法调度(dynamic method dispatch)是一种在运行时而不是编译时调用方法的机制。
动态方法调度也是Java实现运行时多态性的基础。 马克-to-win:要想实现多态,父类和子类必须同时拥有这个同名函数。否则实现不了多态, 底下给出了例子,说明这点。note that when
1)base pointer point to derived class to realize dynamic dispatching,an important requirement is that you also need to
have the same-name method in the base class.refer to the following example of SuperClass.

抽象类和非抽象类二者都可以用来创建对象引用,马克-to-win:用来指向一个子类对象,实现多态。note that abstract and non-abstract class both can dynamically bind for example the following example.

例1.8.1---本章源码

abstract class FigureMark {
    double dime1;
    double dime2;
/*这里的构造函数,是为子类调用使的,不是用来实例化的。马克-to-win: constructor is for subclass's constructor's calling, not for
instantiating. */
    FigureMark(double a, double b) {
        dime1 = a;
        dime2 = b;
    }
    // area is now an abstract method
    abstract void area();
}
class RectangleMark extends FigureMark {
    RectangleMark(double a, double b) {
        super(a, b);
    }
    // 覆盖
 void area() {
        System.out.println("四边形" + dime1 * dime2);
    }
}
class TriangleMark extends FigureMark {
    TriangleMark(double a, double b) {
        super(a, b);
    }
    void area() {
        System.out.println("三角形." + dime1 * dime2 / 2);        
    }
}
public class Test {
    public static void main(String args[]) {
        // FigureMark f = new FigureMark(10, 10); // 错,illegal now
        RectangleMark r = new RectangleMark(9, 5);
        TriangleMark t = new TriangleMark(10, 8);
        FigureMark figref; // 没事,this is OK, no object is created
        figref = r;
        figref.area();
        figref = t;
        figref.area();
/* 基类指针指向派生类的最大意义就在于此, */
        FigureMark[] aa = { r, t };
        for (int i = 0; i < aa.length; i++) {
            aa[i].area();
        }
/* 基类指针指向派生类的最大意义就在于此,马克-to-win:否则你能像下面这样自动话吗?计算机的最大意义不就是自动化, 提高效率吗? */        
        FigureMark[] aa1 = { new RectangleMark(9, 5), new TriangleMark(10, 8) };
        for (int i = 0; i < aa1.length; i++) {
            aa1[i].area();
        }
    }
}

result is:
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0

对于以上例子,r不能指向TriangleMark,t不能指向RectangleMark,而 figref能指向上述二者,这就是基类指针的意义。马 克-to- win:1)for the abve example, r can not point to TriangleMark,while t can not point to RectangleMark, while figref can point to above both, this is the point of the base pointer. 
2)注意数组的效果是非常明显的。

完全把上面的abstract去掉也行, 见下面:

例1.8.2---本章源码

class FigureMark {
    double dime1;
    double dime2;
    FigureMark(double a, double b) {
        dime1 = a;
        dime2 = b;
    }
    void area(){};//非抽象方法,得加个大括号
}
class RectangleMark extends FigureMark {
    RectangleMark(double a, double b) {
        super(a, b);
    }
    // 覆盖
    void area() {
        System.out.println("四边形" + dime1 * dime2);
    }
}
class TriangleMark extends FigureMark {
    TriangleMark(double a, double b) {
        super(a, b);
    }
    void area() {
        System.out.println("三角形." + dime1 * dime2 / 2);       
    }
}
public class Test {
    public static void main(String args[]) {
        FigureMark f = new FigureMark(10, 10); // 现在不错了
        RectangleMark r = new RectangleMark(9, 5);
        TriangleMark t = new TriangleMark(10, 8);
        FigureMark figref; // 没事,this is OK, no object is created
        figref = r;
        figref.area();
        figref = t;
        figref.area();
/* 基类指针指向派生类的最大意义就在于此, */
        FigureMark[] aa = { r, t };
        for (int i = 0; i < aa.length; i++) {
            aa[i].area();
        }
/* 基类指针指向派生类的最大意义就在于此,马克-to-win:否则你能像下面这样自动话吗?计算机的最大意义不就是自动化, 提高效率吗? */       
        FigureMark[] aa1 = { new RectangleMark(9, 5), new TriangleMark(10, 8) };
        for (int i = 0; i < aa1.length; i++) {
            aa1[i].area();
        }
    }
}
结果是:
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0

例1.8.3: 要想实现多态,父类和子类必须同时拥有这个同名函数。马克-to-win:否则实现不了多态,

---本章源码

class SuperClassM_t_w {
    public void printAsuper() {
        System.out.println("父类中a =");
    }
}
class SubClass extends SuperClassM_t_w {
    public void printA() {
        System.out.println("子类中a = " );
    }
}
public class Test {
    public static void main(String args[]) {
        SuperClassM_t_w s1 = new SubClass();
       //  s1.printA();错误, 因为基类中没有printA()这个方法,马克-to-win:出现这种问题,怎么解决,见下面的例子
    }
}


final keyword
防止方法被覆盖 Prevent method overriding

public class A{
public final void show(){


}

防止类被继承,Prevent class inheritance
public final class A{
public void show(){


}


9.向下转型Downcasting:(注意下面的理论没涉及abstract)
Animal a1 = new Cat();
Animal a2 = new Dog();
Dog d = a2;//error必须要向下转型一下
Cat c = a1;//error
Dog d = (Dog)a2;
Cat c = (Cat)a1;

假如我们写成了如下, 就有问题了:

 Animal a1=new Animal();
          Dog d=(Dog)a1; //底下做了个实验说明了这点。马克-to-win:这会报运行时错误,而不是编译错误。runtime error instead of compile error., because a1 is only animal,has no Dog的属性. 

基类指针指向派生类,我们已经很熟了。(视频下载) (全部书籍)假如我们想用派生类反过来指向基类,就需要有两个要求:1)马克-to-win:基类指针开始时指向派生类,2)我们还需要清清楚楚的转型一下。

if you want to use derived class pointer
point to base class, there are two requirements:
1) base class pointer is initially the type of the derived class like Animal a2 = new Dog();
2) 马克-to-win:we still need to explicitly cast it like Dog d = (Dog)a2;

What is the point of downcast? (视频下载) (全部书籍)当一个方法只有子类才有,马克-to-win:不是说基类和子类都有,开始时又是基类指针指向派生类,这时就需要downcast, see the following example. after you cast with SubClass,sc is pure SubClass type.

例1.9.1---本章源码 

class SuperClassM_t_w {
    int a;
    SuperClassM_t_w() {
        a = 5;
    }
    public void printAsuper() {
        System.out.println("父类中a =" + a);
    }
}

class SubClass extends SuperClassM_t_w {
    int a;
    SubClass(int a) {
        this.a = a;
    }
    public void printA() {
        System.out.println("子类中a = " + a);
    }
}
public class Test {
    public static void main(String args[]) {
/* note that new SubClass(10) will call SuperClassM_t_w(), default constructor. */
        SuperClassM_t_w s1 = new SubClass(10);
        s1.printAsuper();//基类指针指向派生类时,马克-to-win: 可以用基类指针调用基类仅有的方法, 但不能调用子类仅有的方法。必须向下强转一下。
        // s1.printA();错误
/* 我们不能去掉下面的话,因为SuperClassM_t_w没有printA方法。马 克-to-wi n:we can not comment the following statement,because SuperClassM_t_w does not have the method of printA, report error */
        SubClass sc = (SubClass) s1;
        sc.printA();
    }
}

 

the result is:

父类中a =5
子类中a = 10

 

instanceof关键字  (视频下载) (全部书籍)


instanceof是java中固有的关键字, 就像main, public一样,用法:aa instanceof AA 就是问aa是不是AA的一个实例, 是的话,就返回真。马 克 - t o   - w i n:当用instance of测试时,马克-to-win:子类的指针是一个instance of父类, 返回值为真,见以下的例子。

例1.9.2---本章源码

class AMark_to_win {
}
class B {
}
class AA extends AMark_to_win {
}
public class Test {
    public static void main(String[] args) {
        AMark_to_win a = new AMark_to_win();
        AMark_to_win aa = new AA();
        B b = new B();
        AA aaa = (AA) aa;
        AA aaaa = new AA();
        System.out.println(a instanceof AA);// false
        System.out.println(aa instanceof AA);// true
        System.out.println(a instanceof AMark_to_win);// true
        System.out.println(b instanceof B);// true
        System.out.println(aa instanceof AMark_to_win);// true//think of AMark_to_win aa=nul;马克-to-win:
        System.out.println(aaa instanceof AA);// true
/* true aaa is an instance of AA,AA is a A, (is relationship. ) */      
        System.out.println(aaa instanceof AMark_to_win);
        System.out.println(aaaa instanceof AMark_to_win);// true,AA is a AMark_to_win, (is relationship. )
        // System.out.println(a instanceof B);//compile error: inconvertible type
    }
}

result is:
false
true
true
true
true
true
true
true



第二节 工具类:

1.Object Class

Object类的作用:m a r k - t o-        w i n:(视频下载) (全部书籍) 在java中,因为所有的类都有共性,所以java的缔造者们把java设计成这样:所有的类都是Object类的直接或间接子类,而且把上述所有类的共性都放在Object类中。这样就可以达到代码重用。All classes in java are subclasses of Object class。

Object类的equals和toString的用法:

下面一组两个例子,马克-to-win:第一个例子是用的父类Object的equals和toString方法,Object的equals是比较对象 在内存当中的地址, 当然不一样了。 而第二个例子Company的equals方法是自己写的,比较的他们的name属性,只要name一样,对象的equals返回的就是真。println (c1);会导致c1的toString被调用(这是语法),第一个例子中c1因为没有toString方法, 所以就用基类Object的toString方法。另外,Object的 toString方法打印出来就是Company@1b67f74,这是Sun公司编的。而后面一个例子的toString方法时咱们自己编的。


例:2.1.1---本章源码

class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
/*
    public String toString() {
        return name;
    }

    public boolean equals(Object o) {
        if (!(o instanceof CompanyMark_to_win))
            return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;
        return name.equals(c.name);
    }
    */
}

public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c3 = new CompanyMark_to_win("xyz");
        System.out.println("c1.equals(c2): " + c1.equals(c2));
        System.out.println("c1.equals(c3): " + c1.equals(c3));
        System.out.println(c1);
    }
}

结果:

c1.equals(c2): false
c1.equals(c3): false
CompanyMark_to_win@1b67f74


例2.1.2---本章源码

class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
/*System.out.println会调用toString这个方法。暂时死记住,这是语法*/  
    public String toString() {
        return name;
    }
    public boolean equals(Object o) {
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/      
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
}

public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c3 = new CompanyMark_to_win("xyz");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        System.out.println("c1.equals(c3): " + c1.equals(c3));
        System.out.println(c1);//这个println会调用子类CompanyMark_to_win的toString方法
    }
}


result is:
c1.equals(c2): true
c1.equals(c3): false
Abc

Object类的hashCode的用法:(新手一定要忽略本节,否则会很惨) (视频下载) (全部书籍)
马 克-to-win:hashCode方法主要是Sun编写的一些数据结构比如Hashtable的hash算法中用到。因为hash很快,所以你往 Hashtable里放东西的时候,他先比一下,里面有没有现有的东西的hashCode和你一样,如果都不一样,证明是新的,就不再运行equals方 法了,直接放进Hashtable里了,很快。如果放的时候,Hashtable里面现有的某东西的hashCode和他一样,他再运行一下 equals,如不一样,则证明是新的,可以放入。equals也一样,证明确实是一样的,不让放入Hashtable。另外,Object的hashCode方法(Sun公司编的)是返回对象的内部地址。equals原始方法判断两个Object是否a==b,内存地址是否等(以下摘自sun的文档:As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.


最后,补充一点,Sun公司Object的equals方法文档上指明:for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes. 假如两个对象的equals返回值一样,hashcode返回值必须一样。但是反过来hashcode等,未必equals等,这就是刚才我们说先判断hashcode是否等,即使等,也要再运行equals,判断是否真的等。马克-to-win:从现实看,按照这逻辑编程,是效率最高,最合理的,本文这里的例子之所以没按照这条,只是为了说明本文所讲的问题。


例2.1.2.1(hashCode都不一样)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/     
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
    public int hashCode() { 
        System.out.println("hashCode 被调用 "+super.hashCode());
        return super.hashCode();
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();

set.add(c1); 
        set.add(c2); 
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一样吗?"+ht.containsKey(c2));
    }
}

输出结果:

equals被调用
c1.equals(c2): true
hashCode 被调用 31168322
hashCode 被调用 17225372
set size:2
hashCode 被调用 31168322
hashCode 被调用 17225372
一样吗?false


结果分析:

当 把c1和c2放入HashSet和Hashtable时,每次放一个对象,就会调用一次HashCode方法。而这里的hashCode是父类 Object的,所以返回内部地址, 不一样。于是HashSet加进去了,size为2,Hashtable也认为c1和c2不一样。HashSet和Hashtable通过 hashCode方法认为c1和c2不一样,即使equals说一样都没用,因为hashcode不一样,就不运行equals了。


例2.1.2.1_b(上例的简版,省略了hashCode方法,直接用父类的)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/     
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
        set.add(c1); 
        set.add(c2); 
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一样吗?"+ht.containsKey(c2));
    }
}

输出结果:

equals被调用
c1.equals(c2): true
set size:2
一样吗?false

例2.1.2.2(hashcode一样,equals不一样。)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/     
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
    public int hashCode() { 
        System.out.println("hashCode 被调用 ");
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc1");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
        set.add(c1); 
        set.add(c2); 
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, c1);
        System.out.println("一样吗?"+ht.containsKey(c2));    
    }
}

输出结果:


equals被调用
c1.equals(c2): false
hashCode 被调用
hashCode 被调用
equals被调用
set size:2
hashCode 被调用
hashCode 被调用
equals被调用
一样吗?false


结果分析:本例hashcode一样,所以equals方法被调用,equals返回值不一样,所以HashSet和Hashtable都认为c1和c2是不同的对象,都接受了, size等于2。

例2.1.2.2(hashcode一样,equals也一样。)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/     
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
    public int hashCode() { 
        System.out.println("hashCode 被调用 ");
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
        set.add(c1); 
        set.add(c2); 
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一样吗?"+ht.containsKey(c2));
    }
}

输出结果:

equals被调用
c1.equals(c2): true
hashCode 被调用
hashCode 被调用
equals被调用
set size:1
hashCode 被调用
hashCode 被调用
equals被调用
一样吗?true

结果分析:本例hashcode一样,所以equals方法被调用,equals返回值一样,所以HashSet和Hashtable都认为c1和c2是相同的对象,只接受了1个, size等于1。


Object类的getClass的用法: (视频下载) (全部书籍)

Object类中有一个getClass方法,m  a  r  k- t  o- w i n:它会返回一个你的对象所对应的一个Class的对象,这个返回来的对象保存着你的原对象的类信息,比如你的原对象的类名叫什么,类里有什么方法,字段等。在高级编程当中用的很多,和反射相关。马克-to-win:现在这个阶段还说不清楚,只能先打个比方,反射就像镜子,你觉得生活当中的镜子有用吗? 

例2.1.3---本章源码

class EmployeeMark {
    public EmployeeMark() {
    }
}
public class Test {
    public static void main(String[] args) {
        EmployeeMark e = new EmployeeMark();
/* public final Class getClass() Returns the runtime class of an object
which can be used to describe the class. */
        Class cls = e.getClass();
        System.out.println("the Class name is: "+ cls.getName());
    }
}


result is:
the Class name is: EmployeeMark


Object类的finalize的用法:(视频下载) (全部书籍)

马克-to-win:java当中有个垃圾回收机制,具体说,就是当一些对象被创建使用之后若不再使用的话{比如(i)对象被置成null.(ii)局部对象(无需置成null)当程序运行到右大括号.(iii)匿名对象刚用完},就会变成垃圾占用空间,JAVA的自动垃圾回收(gc)线程会在适当的时候自动运行,回收内存。马克-to-win: 再具体一点,对象被创建之后,垃圾回收(gc)系统就开始跟踪这个对象的使用情况。垃圾回收系统采用有向图的方式:开始时对象一定是可达的,刚把它置为null时,它也就变成了不可达的了,这时就是所谓的垃圾。垃圾回收系统就会回收这些内存空间。马克-to-win:回收之前,先调用该对象的finalize方法。让其做一些最后的收尾工作。见下例,当p1 = null;时,Java的垃圾回收线程会在适当时间点回收p1对象占据的内存空间。马克-to-win:回 收之前,首先调用p1的finalize()。但是sun公司不保证finalize方法会被及时地自动执行。所以我们加了一句,System.gc ();建议系统回收一下垃圾。gc代表garbage collection(垃圾回收),finalize方法就被执行了。

例2.1.4---本章源码

class PersonMark_to_win {
    String name;
    public PersonMark_to_win(String n) {
        name = n;
    }
    public void finalize() {
        System.out.println(name + " 在进行finalize");
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException {
        PersonMark_to_win p1 = new PersonMark_to_win("张三");
        PersonMark_to_win p2 = new PersonMark_to_win("李四");
        p1 = null;
        // p2 = null;
        System.gc();
        // Thread.sleep(3000);//如果发现gc不执行,就运行一下sleep
    }
}
输出结果:
张三 在进行finalize

例2.1.4_a
class PersonMark_to_win {
    String name;
    public PersonMark_to_win(String n) {
        name = n;
    }
    public void finalize() {
        System.out.println(name + " 在进行finalize");
    }
    void test(){
        PersonMark_to_win pp1 = new PersonMark_to_win("张三jubu");
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException {
        PersonMark_to_win p1 = new PersonMark_to_win("张三");
        PersonMark_to_win p2 = new PersonMark_to_win("李四");
        p2.test();
        System.gc();
        p1 = null;
        // p2 = null;
        System.gc();
         Thread.sleep(3000);//如果发现gc不执行,就运行一下sleep
    }
}

结果:
张三jubu 在进行finalize
张三 在进行finalize

java的垃圾回收与内存泄露的关系:【新手可忽略不影响继续学习】 (视频下载) (全部书籍)

马克-to-win:上一节讲了,(i)对象被置成null.(ii)局部对象(无需置成null)当程序运行到右大括号.(iii)匿名对象刚用完,垃圾回收线程就早早晚晚都能把它过去占的内存给回收了。这么说,java中难道就没有c++的内存泄露的问题了吗?(内存泄露的定义就是: 咱自己程序不用的内存,系统本应回收但由于各种原因却没有回收成功)马克-to-win:答案: 错,java中有内存泄露。下面我们就通过一个例子来说明。下面的例子中,Mark_to_win m作为实例是占有内存空间的。即使后来m = null;把它置为null,垃圾回收线程也回收不了它占有的空间。因为等我们后面集合框架学习了Vector以后,你就会知道:Vector v是一个类似数组的东西。马克-to-win: 任何通过v.add(m);加到Vector里的东西,Vector都会保留一个对它的引用。正因为有这个引用,垃圾回收系统当中的有向图会认为,这个对象还是可达的,所以不会回收它的内存空间。因为size_Make_to_win非常大,(是maxMemory的0.8倍),所以系统最后就崩溃了。马克-to-win: 用专业术语讲,就是开始时是内存泄漏,泄露多了就造成内存溢出了,所以就曝出OutOfMemoryError的错误了。

例2.1.5---本章源码

import java.util.Vector;
class Mark_to_win {
    long data;
}
public class Test {
    static Vector v = new Vector(10);
    public static void main(String[] args) throws InterruptedException {
/*maxMemory:获取系统所能提供的最大内存。*/       
        int size_Make_to_win = (int) (Runtime.getRuntime().maxMemory() * 0.8);
        for (int i = 1; i < size_Make_to_win; i++) {
            Mark_to_win m = new Mark_to_win();
            v.add(m);
            m = null;
        }
        System.out.println("finish");
    }
}
输出结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Vector.ensureCapacityHelper(Unknown Source)
    at java.util.Vector.add(Unknown Source)
    at Test.main(Test.java:13)

上面例题之所以发生内存溢出的原因是:任何通过v.add(m);加到Vector里的东西,Vector都会保留一个对它的引用。马克-to-win: 所以只要我们通过v.remove(m)把这个引用去除。垃圾回收系统,就可以把不用的对象所占用的空间给回收了。这样就不报内存溢出的错误了。见下面的例子。  

例2.1.5_1

import java.util.Vector;
class Mark_to_win {
    long data;
}
public class Test {
    static Vector v = new Vector(10);
    public static void main(String[] args) throws InterruptedException {
/*maxMemory:获取系统所能提供的最大内存。*/       
        int size_Make_to_win = (int) (Runtime.getRuntime().maxMemory() * 0.8);
        for (int i = 1; i < size_Make_to_win; i++) {
            Mark_to_win m = new Mark_to_win();
            v.add(m);
            // 这里是干你的事
            v.remove(m);
            m = null;
        }
        System.out.println("finish");
    }
}
输出结果:

finish


马克-to-win:通过以上的例子,说明了java中存在内存泄露。当泄露的很隐蔽时,后果就会很严重,导致内存溢出。通常市面上有几款查内存泄露的商业或非商业软件,帮助大家监控内存泄露的问题。Rational 公司的Purify,dmalloc,Optimizeit Profiler,JProbe Profiler,JinSight,mtrace,memwatch,马克-to-win:这里我们用jconsole来观察一下前面我们的程序内存泄漏的情况。例2.1.5是有内存泄露的,为了能够更好地观察这个程序内存泄漏的情况,我们加了一句,Thread.sleep(1),让它能够睡一毫秒。

例2.1.5_sleep版本:

import java.util.Vector;
class Mark_to_win {
    long data;
}
public class Test {
    static Vector v = new Vector(10);
    public static void main(String[] args) throws InterruptedException {
/*maxMemory:获取系统所能提供的最大内存。*/       
        int size_Make_to_win = (int) (Runtime.getRuntime().maxMemory() * 0.8);
        for (int i = 1; i < size_Make_to_win; i++) {
            Mark_to_win m = new Mark_to_win();
            Thread.sleep(1);
            v.add(m);
            // 这里是干你的事
            m = null;
        }
        System.out.println("finish");
    }
}
输出结果:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Vector.ensureCapacityHelper(Unknown Source)
    at java.util.Vector.add(Unknown Source)
    at Test.main(Test.java:13)

以上程序运行起来以后,我们启动jconsole来监视它:(新手可忽略此章节)

马克-to-win:从上图可以看出,随着时间的流逝,内存消耗呈现稳定上升状态。基本可以判定,在未来一个时间点,系统会发生内存溢出。即系统崩溃。一旦jconsole呈现这种图形,我们就需要修改程序了。这就是工具如何帮我们发现内存泄漏以及内存溢出。马克-to-win:例2.1.5_1是内存不泄露的, 我们加上Thread.sleep(1), 让它睡一下,从而用jconsole也观察一下, 看一下正常的内存使用应是什么情况的。

例2.1.5_1_sleep:
import java.util.Vector;
class Mark_to_win {
    long data;
}
public class Test {
    static Vector v = new Vector(10);
    public static void main(String[] args) throws InterruptedException {
/*maxMemory:获取系统所能提供的最大内存。*/       
        int size_Make_to_win = (int) (Runtime.getRuntime().maxMemory() * 0.8);
        for (int i = 1; i < size_Make_to_win; i++) {
            Mark_to_win m = new Mark_to_win();
            Thread.sleep(1);
            v.add(m);
            // 这里是干你的事
            v.remove(m);
            m = null;
        }
        System.out.println("finish");
    }
}
输出结果:

finish

以上程序运行起来以后,我们启动jconsole来监视它:(新手可忽略此章节)


曲线呈现平稳波动。内存使用情况正常。

内存泄露总结:【新手可忽略不影响继续学习】 (视频下载) (全部书籍)

马克-to-win: 上节提到了内存泄露实质:程序员认为无用的对象,由于各种原因(粗心等),还有指针或参考指向它, 就造成了泄露。本书不是内存泄露的专业书籍,(内存泄露本身也是java中一个非常高级深入的话题。不适合初学者研究。)只是让作者明白内存泄露的原理。同时泛泛的给出内存泄露的研究方向。
1)单态模式中的静态类生命周期和程序一样长。持有短生命周期的对象时,如未及时释放指向此对象的指针,就会造成泄露。
2)团队开发当中,张三工程师的对象,被李四工程师引用后,张三释放了,但李四并没有释放。
3)使用缓存技术或日志技术时,由于设计成键和时间戳有关系,删除条目时就不能正确删除。造成删除不了,从而内存泄漏。
另外:监听器,数据库连接等不当使用造成泄露。
 

2.数据封装类
下面列出了一些数据封装类。(视频下载) (全部书籍)引入数据封装类有什么用呢?既然它们是类,就有方法,就可以被我们利用。比如,Integer中toHexString方法,可以轻松吧十进制转换成16进制数,马克-to-win:而你int简单类型有这功能吗?


Boolean boolean
Character char
Double double
Float float
Integer int
Long long
Short short
Byte byte
Void void

3.Math 类
用来完成一些常用的数学运算。

例2.2.1---本章源码

public class Test {
    public static void main(String[] args) {
        Integer in = new Integer(5);
        Integer in1 = new Integer("67");
        Boolean b = new Boolean(true);
        System.out.println("Mark 16进制是 "+Integer.toHexString(17));
        System.out.println(in.intValue());
        System.out.println(in1.intValue());
        System.out.println(b.booleanValue());
        System.out.println("马克-to-win Bigger number is " + Math.max(4, 5));
    }
}

 

result is:

Mark 16进制是 11
5
67
true
马克-to-win Bigger number is 5



Assignement:

1) make three classes cat,dog,animal, what is the relationship among them?

2) make three classes jeep, bicycle, vehicle,, what is the relationship among them?

3)make three classes figure,triangle,rectangle, what is the relationship among them?

 

附录:本章源码(视频下载) (全部书籍)


例1.1

class A1Mark {
    static int si=5;
    int i;
    private int j;
    int getJ() {
        return j;
    }
    static int getSi(){
        return si;
    }
    void setij(int x, int y) {
        i = x;
        j = y;
    }
}

class B1 extends A1Mark {
    static int sbi=6;
    int total;
    void sum() {

        total = i + si+getJ()+getSi();
    }
 
    static int getSi(){
        return si*10;
    }
}
public class Test {
    public static void main(String args[]) {
        B1 subOb = new B1();
        subOb.setij(10, 12);
        System.out.println(subOb.i+" "+B1.sbi+" "+subOb.si+" "+subOb.getSi()+" "+B1.si+" "+B1.getSi()+" "+A1Mark.si+" "+A1Mark.getSi());
        subOb.sum();
        System.out.println("Total is " + subOb.total);
    }
}

 

result is:

10 6 5 50 5 50 5 5
Total is 77


例1.2.1

class AMark {
    protected int i;
    public void printI() {
        System.out.println("i=" + i);
    }
}

class B extends AMark {
    public void printIInB() {
        System.out.println("in B i=" + i);
    }
}

public class Test {
    public static void main(String[] args) {
        AMark a=new AMark();
        a.i=7;
        a.printI();
        B b = new B();
        b.i = 10;
        b.printI();
        b.printIInB();
    }
}

result is:
i=7
i=10
in B i=10



例1.2.2

package p1;
public class A {
    protected int i;
    protected void printIProtected() {
        System.out.println("i=" + i);
    }
}

package p2;
import p1.A;
public class Test extends A {
    void printIInB() {
        System.out.println("in B i=" + i);
    }
    public static void main(String[] args) {
        A a=new A();

        Test b = new Test();
        b.i = 10;
        b.printIProtected();
        b.printIInB();
    }

}


运行结果:

i=10
in B i=10


例1.2.3


package p2;
import p1.A;
public class Test1 {
    void printIInB() {

    }
    public static void main(String[] args) {
        A a=new A();

        Test b = new Test();

        b.printIInB();
    }
}


例1.2.4

class A {
    protected int i;
    public int ipub;
    private int ipri;
    public void printI_to_win() {
        System.out.println("i=" + i);
    }
}

class B extends A {
    public void BprintI() {
        System.out.println("i= in B " + i);

        ipub = 9;
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.i = 10;
        b.ipub = 8;
        b.printI_to_win();
        b.BprintI();
    }
}

 

result is:

i=10
i= in B 10


例1.3.1

class AMark_to_win {
    int i;
}

class B extends AMark_to_win {
    int i;

    public B(int x, int y) {
        super.i = x;
        i = y;
    }

    public void show() {
        System.out.println("i in superclass: " + super.i);
        System.out.println("i in subclass: " + i);
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B(2, 3);
        b.show();
    }
}

result is:
i in superclass: 2
i in subclass: 3


例1.3.2

class ZMark_to_win {
    int i;
    void show() {
        System.out.println("i in ZMark_to_win: " + i);
    }
}
class A extends ZMark_to_win {
    public A() {
        super.i = 4;   
    }
    void show() {
        super.show();
        System.out.println("i in A: " + i);
    }
    int i;
}

class B extends A {
    int i;

    public B(int x, int y) {
        super.i = x;   
        i = y;
    }

    public void show() {
        super.show();
        System.out.println("i in B: " + i);
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B(2, 3);
        b.show();
    }
}


结果是:

i in ZMark_to_win: 4
i in A: 2
i in B: 3


例1.4.1

class HealthCardM_t_w {
    double balance = 90;
    double getBalance() {
        return this.balance;
    }
}

class New_Card extends HealthCardM_t_w {
    double balance;
    public New_Card(int in) {
        balance = in;
    }
    double getOldBalanceInNew_Card() {
        return super.balance;
    }
    double getOldBalanceByMythodInNew_Card() {
        return super.getBalance();
    }
    double getThisBalanceInNew_Cardget() {
        return this.balance;
    }
}

public class Test {
    public static void main(String args[]) {
        New_Card myNewCard = new New_Card(500);

        System.out.println("马克-to-win " + myNewCard.getThisBalanceInNew_Cardget());
        System.out.println("马克-to-win " + myNewCard.getOldBalanceInNew_Card());
        System.out.println("马克-to-win " + myNewCard.getOldBalanceByMythodInNew_Card());
        System.out.println("马克-to-win " + myNewCard.getBalance());

    }
}

result is :

马克-to-win 500.0
马克-to-win 90.0
马克-to-win 90.0
马克-to-win 90.0



例1.5.1

class AAAMark_to_win {
    double f(double x, double y) {
        return x * y;
    }
}

class BBB extends AAAMark_to_win {
    double f(double x, double yMark_to_win)

    {
        return x + yMark_to_win;
    }
}

public class Test {
    public static void main(String args[]) {
        AAAMark_to_win a = new AAAMark_to_win();
        System.out.println(a.f(4, 6));
        BBB obj = new BBB();
        System.out.println(obj.f(4, 6));
    }
}

result is:
24.0
10.0

例1.5.2 

class AAAMark_to_win {
    double f(double x, double yMark_to_win) {
        return x * yMark_to_win;
    }
}

class BBB extends AAAMark_to_win {
    double f(double x, double y) {
        return x + y;
    }
}

public class Test {
    public static void main(String args[]) {
        AAAMark_to_win a = new AAAMark_to_win();
        System.out.println(a.f(4, 6));
        BBB obj = new BBB();
        System.out.println(obj.f(4, 6));
   
        AAAMark_to_win obj1 = new BBB();
        System.out.println(obj1.f(4, 6));
    }

}

结果是: 

24.0
10.0
10.0




例1.5.3

class AAAMark_to_win {
    double f(double x, double yMark_to_win) {
        return x * yMark_to_win;
    }
    double f(int x, double y) {
        return x * y*2;
    }
}
class BBB extends AAAMark_to_win {
    double f(double x, double y)
    {
        return x + y;
    }
}
public class Test {
    public static void main(String args[]) {
        BBB obj = new BBB();
        
        System.out.println(obj.f(4, 6.0));
        
        System.out.println(obj.f(4.0, 6));
    }
}

结果是:

48.0
10.0



例1.6.1: 

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside AAAMark_to_win's constructor.");
    }
    AAAMark_to_win(int j) {
        System.out.println(j);
    }
}
class BBB extends AAAMark_to_win {
    BBB() {
        super(3);
        System.out.println("Inside BBB's constructor.");
    }
    BBB(int i) {
        System.out.println(i);
    }
}
class C extends BBB {
    C(int a) {
   
        super(1);
        System.out.println("Inside C's constructor.");
    }
}

public class Test {
    public static void main(String args[]) {

        C c = new C(5);
    }
}

result:

Inside AAAMark_to_win's constructor.
1
Inside C's constructor.


例1.6.2: 

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside AAAMark_to_win's constructor.");
    }
}
class BBB extends AAAMark_to_win {
    BBB(double g) {
        System.out.println("Inside BBB's constructor.");
    }
}
class C extends BBB {
    C(int a) {
        super(5.9);
        System.out.println("Inside C's constructor1.");
    }
}
public class Test {
    public static void main(String args[]) {
        C c = new C(5);
    }
}

 

result is:

Inside AAAMark_to_win's constructor.
Inside BBB's constructor.
Inside C's constructor1.


例1.6.3:

class AAAMark_to_win {
    AAAMark_to_win() {
        System.out.println("Inside A's constructor.");
    }
}
class BBB extends AAAMark_to_win {
    BBB() {
        System.out.println("Inside BBB's constructor.");
    }
}
class C extends BBB {
    C() {
        System.out.println("Inside C's constructor.");
    }
}
public class Test {
    public static void main(String args[]) {
        C c = new C();
    }
}

result is:

Inside A's constructor.
Inside BBB's constructor.
Inside C's constructor.



例1.7.1:

abstract class Nothing {
    void nothing() {
        System.out.println("nothing");
    }
}
abstract class VehMark_to_win {
    abstract void steer();
    abstract void move();
}
class Bike extends VehMark_to_win {
    void steer() {
        System.out.println("Turn handlebar");
    }
    void move() {
        System.out.println("move");
    }
}
abstract class Cart extends VehMark_to_win {
   
}
abstract class Car extends VehMark_to_win {
    void steer() {
        System.out.println("Turn steering wheel");
    }
    void move() {
        System.out.println("move");
    }
}
class Lim extends Car {
   
}
public class Test {
    public static void main(String[] args) {
        Nothing n0;
        Bike b = new Bike();
        Lim l = new Lim();
        b.steer();
        l.steer();
    }
}


result is:
Turn handlebar
Turn steering wheel


例1.8.1:

abstract class FigureMark {
    double dime1;
    double dime2;

    FigureMark(double a, double b) {
        dime1 = a;
        dime2 = b;
    }

    abstract void area();
}
class RectangleMark extends FigureMark {
    RectangleMark(double a, double b) {
        super(a, b);
    }

    void area() {
        System.out.println("四边形" + dime1 * dime2);
    }
}
class TriangleMark extends FigureMark {
    TriangleMark(double a, double b) {
        super(a, b);
    }
    void area() {
        System.out.println("三角形." + dime1 * dime2 / 2);        
    }
}
public class Test {
    public static void main(String args[]) {

        RectangleMark r = new RectangleMark(9, 5);
        TriangleMark t = new TriangleMark(10, 8);
        FigureMark figref;
        figref = r;
        figref.area();
        figref = t;
        figref.area();

        FigureMark[] aa = { r, t };
        for (int i = 0; i < aa.length; i++) {
            aa[i].area();
        }
       
        FigureMark[] aa1 = { new RectangleMark(9, 5), new TriangleMark(10, 8) };
        for (int i = 0; i < aa1.length; i++) {
            aa1[i].area();
        }
    }
}

result is:
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0

例1.8.2:

class FigureMark {
    double dime1;
    double dime2;
    FigureMark(double a, double b) {
        dime1 = a;
        dime2 = b;
    }
    void area(){};
}
class RectangleMark extends FigureMark {
    RectangleMark(double a, double b) {
        super(a, b);
    }

    void area() {
        System.out.println("四边形" + dime1 * dime2);
    }
}
class TriangleMark extends FigureMark {
    TriangleMark(double a, double b) {
        super(a, b);
    }
    void area() {
        System.out.println("三角形." + dime1 * dime2 / 2);       
    }
}
public class Test {
    public static void main(String args[]) {
        FigureMark f = new FigureMark(10, 10); // 现在不错了
        RectangleMark r = new RectangleMark(9, 5);
        TriangleMark t = new TriangleMark(10, 8);
        FigureMark figref;
        figref = r;
        figref.area();
        figref = t;
        figref.area();

        FigureMark[] aa = { r, t };
        for (int i = 0; i < aa.length; i++) {
            aa[i].area();
        }
     
        FigureMark[] aa1 = { new RectangleMark(9, 5), new TriangleMark(10, 8) };
        for (int i = 0; i < aa1.length; i++) {
            aa1[i].area();
        }
    }
}
结果是:
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0
四边形45.0
三角形.40.0


class SuperClassM_t_w {
    public void printAsuper() {
        System.out.println("父类中a =");
    }
}
class SubClass extends SuperClassM_t_w {
    public void printA() {
        System.out.println("子类中a = " );
    }
}
public class Test {
    public static void main(String args[]) {
        SuperClassM_t_w s1 = new SubClass();

    }
}



例1.9.1: 

class SuperClassM_t_w {
    int a;
    SuperClassM_t_w() {
        a = 5;
    }
    public void printAsuper() {
        System.out.println("父类中a =" + a);
    }
}

class SubClass extends SuperClassM_t_w {
    int a;
    SubClass(int a) {
        this.a = a;
    }
    public void printA() {
        System.out.println("子类中a = " + a);
    }
}
public class Test {
    public static void main(String args[]) {

        SuperClassM_t_w s1 = new SubClass(10);
        s1.printAsuper();
        SubClass sc = (SubClass) s1;
        sc.printA();
    }
}

 

the result is:

父类中a =5
子类中a = 10

 


例1.9.2:

class AMark_to_win {
}
class B {
}
class AA extends AMark_to_win {
}
public class Test {
    public static void main(String[] args) {
        AMark_to_win a = new AMark_to_win();
        AMark_to_win aa = new AA();
        B b = new B();
        AA aaa = (AA) aa;
        AA aaaa = new AA();
        System.out.println(a instanceof AA);
        System.out.println(aa instanceof AA);
        System.out.println(a instanceof AMark_to_win);
        System.out.println(b instanceof B);
        System.out.println(aa instanceof AMark_to_win);
        System.out.println(aaa instanceof AA);
 
        System.out.println(aaa instanceof AMark_to_win);
        System.out.println(aaaa instanceof AMark_to_win);
    }
}

result is:
false
true
true
true
true
true
true
true


例:2.1.1

class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }

}

public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c3 = new CompanyMark_to_win("xyz");
        System.out.println("c1.equals(c2): " + c1.equals(c2));
        System.out.println("c1.equals(c3): " + c1.equals(c3));
        System.out.println(c1);
    }
}

结果:

c1.equals(c2): false
c1.equals(c3): false
CompanyMark_to_win@1b67f74


例2.1.2:

class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }

    public String toString() {
        return name;
    }
    public boolean equals(Object o) {
  
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;
        return name.equals(c.name);
    }
}

public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c3 = new CompanyMark_to_win("xyz");
        System.out.println("c1.equals(c2): " + c1.equals(c2));
        System.out.println("c1.equals(c3): " + c1.equals(c3));
        System.out.println(c1);
    }
}


result is:
c1.equals(c2): true
c1.equals(c3): false
Abc


例2.1.3:

class EmployeeMark {
    public EmployeeMark() {
    }
}
public class Test {
    public static void main(String[] args) {
        EmployeeMark e = new EmployeeMark();

        Class cls = e.getClass();
        System.out.println("the Class name is: "+ cls.getName());
    }
}


result is:
the Class name is: EmployeeMark


例2.1.4---本章源码

class PersonMark_to_win {
    String name;
    public PersonMark_to_win(String n) {
        name = n;
    }
    public void finalize() {
        System.out.println(name + " 在进行finalize");
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException {
        PersonMark_to_win p1 = new PersonMark_to_win("张三");
        PersonMark_to_win p2 = new PersonMark_to_win("李四");
        p1 = null;
        System.gc();
    }
}
输出结果:
张三 在进行finalize

 

例2.1.5

import java.util.Vector;
class Mark_to_win {
    long data;
}
public class Test {
    static Vector v = new Vector(10);
    public static void main(String[] args) throws InterruptedException {
        int size_Make_to_win = (int) (Runtime.getRuntime().maxMemory() * 0.8);
        for (int i = 1; i < size_Make_to_win; i++) {
            Mark_to_win m = new Mark_to_win();
            v.add(m);
            m = null;
        }
        System.out.println("finish");
    }
}
输出结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Vector.ensureCapacityHelper(Unknown Source)
    at java.util.Vector.add(Unknown Source)
    at Test.main(Test.java:13)