JavaSE Day10

本节内容

 1.对象与对象的关系

2.值传递/引用传递

3.抽象类

4.接口

5.多态

6.向上转型/向下转型

一、对象与对象的关系

Java中对象与对象的一对一关系 :

比如我们的一对夫妇他们之间的关系就是一对一,在Java中的一对一关系,实质是将一个类当做另一个类的属性。

package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public class Husband {
    
    String  name;
    
    int age;
    
    //老公与妻子的一对一关系
    
    Wife wife;

}
package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public class Wife {
    
      String  name;
    
      int age;
      //妻子与老公的一对一关系
      Husband husband;
      

}

Java中对象与对象的一对多关系 :

比如我们的部门与员工之间的关系,一个部门有多个员工,这是将一个员工数组当做部门类的一个属性。

package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public class Emp {
    
    int e_id;
    
    String name;
    
    int age;
    
    char sex;
    
    String address;
    
    double salary;
    
    
    
    
    

}
package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public class Dept {
    
    int dept_id;
    
    String  dept_name;
    //部门与员工的一对多关系
     Emp[] emp;
    
    

}

二、方法传值

首先要说明的是java中是没有指针的,java中只存在值传递,只存在值传递!!!  然而我们经常看到对于对象(数组,类,接口)的传递似乎有点像引用传递,可以改变对象中某个属性的值。但是不要被这个假象所蒙蔽,实际上这个传入函数的值是对象引用的拷贝,即传递的是引用的地址值,所以还是按值传递

值传递

public class Test3 {
    public static void change(int a){
        a=50;
    }
    public static void main(String[] args) {
        int a=10;
        System.out.println(a);
        change(a);
        System.out.println(a);
    }
}

运行结果: 10 10

引用传递

public class Test3 {
    public static void change(int []a){
        a[0]=50;
    }
    public static void main(String[] args) {
        int []a={10,20};
        System.out.println(a[0]);
        change(a);
        System.out.println(a[0]);
    }
}

 运行结果: 10  50

String

public class Test {
    public static void change(String s){
        s="zhangsan";
    }
    
    public static void main(String[] args) {
        String s=new String("lisi");
        System.out.println(s);
        change(s);
        System.out.println(s);
    }
}

 运行结果:  list  list

三、抽象类

    抽象类的定义

普通类是一个完善的功能类,可以直接产生实例化对象,并且在普通类中可以包含有构造方法、普通方法、static方法、常量和变量等内容。而抽象类是指在普通类的结构里面增加抽象方法的组成部分。

那么什么叫抽象方法呢?在所有的普通方法上面都会有一个“{}”,这个表示方法体,有方法体的方法一定可以被对象直接使用。而抽象方法,是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰

拥有抽象方法的类就是抽象类,抽象类要使用abstract关键字声明。

package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public abstract class Animal {
    //普通方法
    public  void sleep(){
        System.out.println("有方法体");
    }
    
    //抽象方法    没有方法体  使用 abstract 关键词修饰
    public abstract void eat();

}

抽象类的使用:

       抽象类不能实例化(不能创建对象)  为什么?????

因为抽象类中存在抽象方法,我们知道一个如果能实例化,通过实例化对象就可以调用类中的属性与方法,而抽象方法没有方法体,没有方法体就不能调用,既然不能调用方法,那么也就不能实例化。

抽象类的使用原则如下:
(1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
(2)抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;
(3)抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
(4)子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。)

package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public abstract class Animal {
    //普通方法
    public  void sleep(){
        System.out.println("有方法体");
    }
    
    //抽象方法    没有方法体  使用 abstract 关键词修饰
    public abstract void eat();

}
package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public class Dog extends Animal{   //dog类是Animal抽象类的子类,是一个普通类
    
    
    
     //强制重写抽象方法
    @Override
    public void eat() {  
        // TODO Auto-generated method stub
        
    }

}

现在就可以清楚的发现:
(1)抽象类继承子类里面有明确的方法覆写要求,而普通类可以有选择性的来决定是否需要覆写;
(2)抽象类实际上就比普通类多了一些抽象方法而已,其他组成部分和普通类完全一样;
(3)普通类对象可以直接实例化,但抽象类的对象必须经过向上转型之后才可以得到。

虽然一个类的子类可以去继承任意的一个普通类,可是从开发的实际要求来讲,普通类尽量不要去继承另外一个普通类,而是去继承抽象类。

三、抽象类的使用限制

(1)抽象类中有构造方法么?
由于抽象类里会存在一些属性,那么抽象类中一定存在构造方法,其存在目的是为了属性的初始化。
并且子类对象实例化的时候,依然满足先执行父类构造,再执行子类构造的顺序。

package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public abstract class Animal {
    
    //构造方法
    public Animal() {
         System.out.println("Animal类的构造方法");
    }

    //普通方法
    public  void sleep(){
        System.out.println("有方法体");
    }
    
    //抽象方法    没有方法体  使用 abstract 关键词修饰
    public abstract void eat();

}
package com.xk;
/*
 *作者:吴志龙
 *日期:2018年7月30日  
*/
public class Dog extends Animal{   //dog类是Animal抽象类的子类,是一个普通类
    
    public Dog() {
         System.out.println("Dog 类的构造方法");
    }
    
     //强制重写抽象方法
    @Override
    public void eat() {  
        // TODO Auto-generated method stub
        
    }
    
    
    public static void main(String[] args) {
        //向上转型
         Animal  animal =new Dog();
        
        
    }

    

}

运行结果

Animal类的构造方法
Dog 类的构造方法

(2)抽象类可以用final声明么?
不能,因为抽象类必须有子类,而final定义的类不能有子类;

抽象类的应用:抽象类是模板式设计

例如,现在有三类事物:
(1)机器人:充电,工作;
(2)人:吃饭,工作,睡觉;
(3)猪:进食,睡觉。
现要求实现一个程序,可以实现三种不同事物的行为

四、接口

接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象

[public] interface InterfaceName {
 
}

接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。

定义:

Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)

接口的特点:

 

  1. Java接口中的成员变量默认都是public,static,final类型的(都可省略),必须被显示初始化,即接口中的成员变量为常量(大写,单词之间用”_”分隔);
  2. Java接口中的方法默认都是public,abstract类型的(都可省略),没有方法体,不能被实例化;
  3. Java接口中只能包含public,static,final类型的成员变量和public,abstract类型的成员方法;
  4. 接口中没有构造方法,不能被实例化;
  5. 一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接口
  6. Java接口必须通过类来实现它的抽象方法;
  7. 当类实现了某个Java接口时,它必须实现接口中的所有抽象方法,否则这个类必须声明为抽象类;
  8. 不允许创建接口的实例(实例化),但允许定义接口类型的引用变量,该引用变量引用实现了这个接口的类的实例;
  9. 一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继承。

现在有这样一个需求:

         现在学校的招待环境:  招待的人员有: 学生   老师   家长

学生:  在食堂吃饭、在宿舍住宿

老师:教师食堂    、学校公寓

家长: 招待所吃饭  、招待所

理论上,当然可以对每个不同身份的人各定义一个对应的类,并实现各自的方法,但是观察这写类,可以归纳出其有一个共同的模板,即“人”的“食、宿”问题。这时候,就可以发挥接口的功能了

interface Person{  
    void eat();  
    void sleep();  
}  

class Student implements Person{  
    public void eat(){  
       System.out.println("学生去食堂吃饭!");  
    }  
    public void sleep(){  
       System.out.println("学生回寝室睡觉!");  
    }  
}  

class Teacher implements Person{  
    public void eat(){  
       System.out.println("教师去教工餐厅吃饭!");  
    }  
    public void sleep(){  
       System.out.println("教师回学校公寓睡觉!");  
    }  
}  
 class Parents implements Person{  
    publicvoid eat(){  
       System.out.println("家长去招待所饭馆吃饭!");  
    }  
    public void sleep(){  
       System.out.println("家长回招待所睡觉!");  
    }  
}  

public class PersonInterface{  
         public static void main(String[] args)  
         {  
                   Person p=new Student();  
                   p.eat();  
                   p.sleep();  
                   p=new Teacher();  
                   p.eat();  
                   p.sleep();  
                   p=new Parents();  
                   p.eat();  
                   p.sleep();  
         }  
} 
View Code

现在需要添加一些功能,即现在需要添加“外宾、上级领导”两类角色,并且以后工具需要还要添加相应的身份角色的人进来,此时,只需要根据需要添加“外宾”类、“领导”类,而主类仍然可以拿来就用,无需进行更多的修改。此时就可以显示出接口的作用了。

class Foreign implements Person{  
    publicvoid eat(){  
       System.out.println("外宾去酒店吃饭!");  
    }  
    public void sleep(){  
       System.out.println("外宾回酒店睡觉!");  
    }  
}  

class Leader implements Person{  
    publicvoid eat(){  
       System.out.println("领导去宾馆吃饭!");  
    }  
    public void sleep(){  
       System.out.println("外宾回宾馆睡觉!");  
    }  
}
View Code

通过继承来扩展接口

通过继承,可以很容易地在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口。

interface Monster {// 怪物
    void menace();// 威胁
}

interface DangerousMonster extends Monster {
    void destroy();// 破坏
}

interface Lethal {// 致命的
    void kill();// 杀死
}

class DragonZilla implements DangerousMonster {

    @Override
    public void menace() {
        // TODO Auto-generated method stub

    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }
}

interface Vampire extends DangerousMonster, Lethal {// 吸血鬼
    void drinkBlood();
}

class VeryBadVampire implements Vampire {
    @Override
    public void menace() {
        // TODO Auto-generated method stub

    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void kill() {
        // TODO Auto-generated method stub

    }

    @Override
    public void drinkBlood() {
        // TODO Auto-generated method stub

    }

}

public class HorrorShow {
    static void u(Monster b) {
        b.menace();
    }

    static void v(DangerousMonster d) {
        d.menace();
        d.destroy();
    }

    static void w(Lethal l) {
        l.kill();
    }

    static void x(Vampire v) {
        v.menace();
        v.destroy();
        v.kill();
        v.drinkBlood();
    }

    public static void main(String[] args) {
        DangerousMonster barney = new DragonZilla();
        u(barney);
        v(barney);

        Vampire vlad = new VeryBadVampire();
        u(vlad);
        v(vlad);
        w(vlad);
        x(vlad);

    }

}
View Code

DangerousMonster是Monster的直接扩展,它产生了一个新接口。DragonZilla中实现了这个接口。

在Vampire中使用的语法仅适用于接口继承。一般情况下,只可以将extends用于单一类,但是可以引用多个基类接口。

一 接口和抽象类的相似性

1 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。

2 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

二 接口和抽象类的区别

1 接口里只能包含抽象方法,静态方法和默认方法,不能为普通方法提供方法实现,抽象类则完全可以包含普通方法。

2 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则既可以定义普通成员变量,也可以定义静态常量。

3 接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

4 接口里不能包含初始化块,但抽象类里完全可以包含初始化块。

5 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承不足。

五、多态:

定义:多态:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式

一种事物多种表现形态。

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法

多态存在的三个必要条件

一、要有继承;

二、要有重写;

三、父类引用指向子类对象

Java中的多态表现有:

静态多态: 在编译阶段体现: 方法的重载

多态多态:在代码运行阶段体现: 方法的重写。

多态的好处:

 提高了代码的维护性(继承保证)
 提高了代码的扩展性(由多态保证)

六、向上转型/向下转型

要转型,首先要有继承。继承是面向对象语言中一个代码复用的机制,简单说就是子类继承了父类中的非私有属性和可以继承的方法,然后子类可以继续扩展自己的属性及方法

  向上转型:子类对象转为父类,父类可以是接口。公式:Father f = new Son();Father是父类或接口,son是子类。

       向下转型:父类对象转为子类。公式:Son s = (Son)f;

 

public class Human {

    public void sleep() {
        System.out.println("Human sleep..");
    }

    public static void main(String[] args) {
        Human h = new Male();// 向上转型
        h.sleep();
        Male m = new Male();// 干嘛要向上转型
        m.sleep();
        // h.speak();此方法不能编译,报错说Human类没有此方法
    }
}

class Male extends Human {
    @Override
    public void sleep() {
        System.out.println("Male sleep..");
    }

    public void speak() {
        System.out.println("I am Male");
    }
}

class Female extends Human {
    @Override
    public void sleep() {
        System.out.println("Female sleep..");
    }

    public void speak() {
        System.out.println("I am Female");
    }
}
View Code

向上转型与向下转型可以看作是数据类型的转换:

向上转型:可以看作是小类型转大类型  自动转换

向下转型:可以看作是大类型转小类型  强制转换。

向下转型:注意看转的父类引用是不是这个子类的实例,如果不是就不能转,如果是才能转。

   

      

原文地址:https://www.cnblogs.com/wuzhilong/p/9391736.html