Java学习(1)多态

今天阴天多云,天气渐冷,不关窗户就会打喷嚏,秋意浓哦😊,那么来总结今天学习了什么

JAVA基础:多态(polymorphic)

直接贴代码好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
多态的概念呢比较简单,就是同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果

这样,就实现了多态,同样是Parent类的实例,p.call 调用的是Son类的实现、p1.call调用的是Daughter的实现。 有人说,你自己定义的
时候不就已经知道p是son,p1是Daughter了么。但是,有些时候你用到的对象并不都是自己声明的啊 。 比如Spring 中的IOC出来的对象,
你在使用的时候就不知道他是谁,或者说你可以不用关心他是谁。根据具体情况而定。

另外,还有一种说法,包括维基百科也说明,多态还分为动态多态和静态多态。 上面提到的那种动态绑定认为是动态多态,
因为只有在运行期才能知道真正调用的是哪个类的方法。

还有一种静态多态,一般认为Java中的函数重载是一种静态多态,因为他需要在编译期决定具体调用哪个方法、

关于这个动态静态的说法,我更偏向于重载和多态其实是无关的。

但是也要看情况,普通场合,我会认为只有方法的重写算是多态,毕竟这是我的观点。但是如果在面试的时候,我“可能”会认为重载也算是多态,
毕竟面试官也有他的观点。我会和面试官说:我认为,多态应该是一种运行期特性,Java中的重写是多态的体现。不过也有人提出重载是
一种静态多态的想法,这个问题在StackOverflow等网站上有很多人讨论,但是并没有什么定论。我更加倾向于重载不是多态。

这样沟通,既能体现出你了解的多,又能表现出你有自己的思维,不是那种别人说什么就是什么的。
*/
public class Daughter extends Parent {
    public void call(){
        System.out.println("Im daughter");
    }
}

public class Parent {
    public void call(){
        System.out.println("Im father");
    }

}

public class Son extends Parent {
    public void call(){
        System.out.println("Im son");
    }
}

public class test_Polymorphism {
    public static void main(String[] args) {
        Parent p1 = new Son();      //3.父类的引用指向子类的对象
        Parent p2 = new Daughter(); //3.父类的引用指向子类的对象

        p1.call();  // Im son
        p2.call();  // Im daughter
    }
}

为了实现运行期的多态,或者说是动态绑定,需要满足三个条件。

有类继承或者接口实现子类要重写父类的方法父类的引用指向子类的对象

JAVA基础:重写(Overriding)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

public class Dog {
    public void bark(){
        System.out.println("woof"); // 狗吠声
    }

}

public class Hound extends Dog {
    public void sniff(){
        System.out.println("sniff"); // sniff吸气(声);抽鼻子(声);嗅;闻;感觉;察觉;微小的可能性
    }
    public void bark(){   // 重写 bark方法
        System.out.println("bowl  方法重写");
    }
}

public class test_overriding {
    public static void main(String[] args) {
        Dog d1 = new Hound();

        d1.bark();    // 重写 动态多态性

    }
}

上面的例子中,dog对象被定义为Dog类型。在编译期,编译器会检查Dog类中是否有可访问的bark()方法,只要其中包含bark()方法,那么就可以编译通过。 在运行期,Hound对象被new出来,并赋值给dog变量,这时,JVM是明确的知道dog变量指向的其实是Hound对象的引用。 所以,当dog调用bark()方法的时候,就会调用Hound类中定义的bark()方法。

这就是所谓的动态多态性

JAVA基础:JAVA中只有值传递???

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class User {
    private String name;
    private String gender;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

public class ParamTest {
    public static void main(String[] args) {
        ParamTest p1 = new ParamTest();

        User user = new User();
        user.setName("jerry");
        user.setGender("female");
        p1.pass(user);
        System.out.println(user.getName()+" "+user.getGender());

    }

    public void pass(User user){   // 这实际上是在堆里边的地址值传递 会改变堆里边的内容
        // user = new User();      // 如果添加这局话就是对内容的副本 新对象 在堆里边会new一个新对象
        user.setName("jon");
        user.setGender("male");
        System.out.println(user.getName()+" "+user.getGender());
    }
}

所以说,Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。

总结: 无论是值传递还是引用传递,其实都是一种求值策略(Evaluation strategy)。在求值策略中,还有一种叫做按共享传递(call by sharing)。 其实Java中的参数传递严格意义上说应该是按共享传递。

按共享传递,是指在调用函数时,传递给函数的是实参的地址的拷贝(如果实参在栈中,则直接拷贝该值)。 在函数内部对参数进行操作时,需要先拷贝的地址寻找到具体的值,再进行操作。如果该值在栈中,那么因为是直接拷贝的值,所以函数内部对参数进行操作不会对外部变量产生影响。 如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝所以函数内对值的操作对外部变量是可见的。

简单点说,Java中的传递,是值传递,而这个值,实际上是对象的引用。

而按共享传递其实只是按值传递的一个特例罢了。所以我们可以说Java的传递是按共享传递或者说Java中的传递是值传递。

以上是GitHub项目大佬的论点,我感觉那么不管是堆里边new的地址值还是copy副本的值都是数值,所以传递的是数值,区分的关键是确定好是否有一个副本出现。

JAVA基础:内存的分配

捕获.PNG

JAVA基础:组合(Composition)

详细可以看这个博客,是《java编程思想》的提炼。第7章:复用类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class WaterSource {     // 水资源类
    private String s;

    WaterSource() {     // 无参数构造方法
        System.out.println("WaterSource()");
        s = "Constructed";
    }

    public String toString() {      // 也是一个重写overriding
        return s;
    }
}

public class SprinklerSystem {
    private String valve1, valve2, valve3, valve4;      // String不是基本类型是引用类型
    private WaterSource source = new WaterSource();     // 会调用默认构造方法
    private int i;
    private float f;

    /*
    toString()每一个非基本类型的对象都有这样一个方法,而且当编译器需要一个String而你却只有一个对象时,该方法便会被调用。所以,
    代码      " source = " + source;
    编译器将会得知你想要将一个String对象同另外一个对象相加,因此编译器会告诉你:"我将调用 toString(),把suorce转换成String!”
    这样做之后,他就能够将两个String连接在一起并将结果传递给System.out.println(sprinklers),每当想要把使用所创建的类具备这样的
    行为时,仅需要编写一个toString()方法即可

    这是不是抽象的意思呢?声明了但是没有写具体的方法体
     */

    public String toString() {    // 重写方法
        return
                "valve1 = " + valve1 + " " +
                "valve2 = " + valve2 + " " +
                "valve3 = " + valve3 + " " +
                "valve4 = " + valve4 + "\n" +
                " i " + i + " " + " f= " + f + " " +
                "source = " + source;
    }

    // main方法
    public static void main(String[] args) {
        SprinklerSystem sprinklers= new SprinklerSystem();
        System.out.println(sprinklers);     // 这里要输出一个对象引用,所以会去寻找toString()方法来调用
    }


}

JAVA基础:继承(Inheritance)

书上的代码在每个类中都写了main方法感觉很奇妙,书上说是为了方便对代码进行单元测试。记得之前有个Junit的单元测试工具,只是有印象。代码这样写还是挺奇妙的,最后一句话还添加了对前一个类的main方法调用,嗯,很灵活,长见识了。😊

而且!书中还说要慎用继承这个特性!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Cleanser{
    private String s = "Cleanser ";
    public void append(String a){s+=a;}
    public void dilute(){append("a ");}
    public void apply(){append("b ");}
    public void scrub(){append("c ");}
    public String toString(){return s;}


    /*
    可以为每个类都创建mian方法,这样会使每个类的单元测试都变得简单易行,而且在完成单元测试后也无需删除main可以留着下回用。
     */

    public static void main(String[] args) {
        Cleanser x = new Cleanser();
        x.dilute();x.apply();x.scrub();
        System.out.println(x);
    }
}

public class Detergent extends Cleanser {
    // 修改父类中的各种方法
    public void scrub(){
        append("C ");
        super.scrub();
    }

    //
    public void foam(){
        append("d ");
    }

    public static void main(String[] args) {
        Detergent x = new Detergent();
        x.dilute();
        x.apply();
        x.scrub();
        x.foam();
        System.out.println(x);  // Cleanser a b C c d
        System.out.println("测试基类结果:");
        // Detergent.main()明确调用了Cleanser.main()方法,并将从命令行获取的参数传递给了它。当然也可以传递任意的String()数组
        Cleanser.main(args);   // Cleanser a b c

    }

}

JAVA基础:代理

代理:java并没有提供对它的直接支持.这是继承与组合之间的中庸之道.因为我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的所有方法(就像继承)—-《JAVA编程思想》P130

其实就是在一个类中新建了另一个类的实例,通过这个实例来调用方法使用方法,这样就不用直接写代码了(这样叫解耦??),另外IDEA对代理可以自动生成代码,很给力,书中竟然也有提到,我是大四才用到IDEA,书中自有黄金屋啊!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class SpaceShipControl {
    void up(int v){}
    void down(int v){}
    void left(int v){}
    void right(int v){}
    void forward(int v){}
    void back(int v){}
    void turboBoost(){}
}
public class SpaceShipDelegation {
    private String name;

    private SpaceShipControl controls = new SpaceShipControl();   //  创建一个飞船空制类的实例

    public SpaceShipDelegation(String name){
        this.name = name;
    }


    //  代理方法 idea 自动生成 在controls实例对象右击选择Generate,找到Delegate Methods 点击即可有下列代码
    public void up(int v) {
        controls.up(v);
    }

    public void down(int v) {
        controls.down(v);
    }

    public void left(int v) {
        controls.left(v);
    }

    public void right(int v) {
        controls.right(v);
    }

    public void forward(int v) {
        controls.forward(v);
    }

    public void back(int v) {
        controls.back(v);
    }

    public void turboBoost() {
        controls.turboBoost();
    }


    public static void main(String[] args) {
         SpaceShipDelegation protector = new SpaceShipDelegation("NSEA Protector");
         protector.forward(100);
    }
}

JAVA基础:toString()

这个小朋友是怎么回事呢,toString()在需要的时候需要自己写,而且是重写,每一个非基本类型对象都有一个toString()方法。

` “source = “ + source; `

这样一个String类型的source与一个 “” 括起来的内容加起来,需要把引用类型的对象用toString()方法来变成字符串,然后传递给sout函数输出。

可以看看组合那段代码。

RE:foobar2000

搜索cue文件的时候发现用foobar2000可以打开,啊,有多久没有用这个播放器了,初中的时候下载后用了很长一段,后来换笔记本就忘记了。 很好的播放器,可以方便得分割cue这样的CD文件,理解不深入,逛了逛论坛发现还有很多插件可以提升质感,我是下载了汉化版,功能很棒了,后续有时间在研究吧。

今日总结

不满意今天得用工程度,中午还是打了游戏,连着玩了两盘,垃圾游戏,然后睡觉睡到了下午四点多,没有锻炼,blabla。。。

好的方面是起码在做事,会学习,心态也平稳多了,很抱歉前几天对自己那么消极,也让爸妈很担心。相信自己呦!

明天除了看Java再看看html吧,然后得出去跑跑步了,好几天都没跑步,还有记得吃药!