java基础学习之面向对象高级知识(三)

基本概念

  • 面向对象高级部分
    • 继承性
      • 继承的实现
      • 继承的限制
    • 覆写
      • 方法的覆写
      • 属性的覆盖
    • 继承案例
      • 开发数组的父类
      • 开发排序类
      • 开发反转类
    • final关键字
    • 多态性
    • 抽象类
      • 抽象类定义
      • 抽象类的相关限制
      • 抽象类的应用-模板设计模式
    • 接口
      • 接口的定义
      • 接口的实际应用-标准
      • 接口的应用——工厂设计模式(Factory)
      • 接口的应用——代理设计模式(Proxy)
      • 抽象类与接口的区别
    • Object类
      • Object类的基本定义
      • 取得对象信息:toString()
      • 对象比较:equals()
      • Object类与引用数据类型
    • 匿名内部类
    • 基本数据类型包装类
      • 装箱与拆箱操作
      • 自动装箱与自动拆箱操作
      • 数据类型的转换

面向对象高级部分

继承性

继承的实现

继承性严格来讲就是扩充一个类已有的功能。

  • extends应该翻译为扩充,为了方便理解,称其为继承;
  • 子类又被称位派生类;
  • 父类又被称为超类;

继承的基本实现

// An highlighted block
class Person{
     
    private String name;
    private int age;

    public String getName() {
     
        return name;
    }

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

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }
}
class Student extends Person{
     

}
public class Demo {
     
    public static void main(String[] args) {
     
        Student stu = new Student();
        stu.setName("张三");
        stu.setAge(20);
        System.out.println("姓名:"+stu.getName()+",年龄:"+stu.getAge());
    }
}
执行结果:姓名:张三,年龄:20

在子类中扩充方法

// An highlighted block
class Person{
     
    private String name;
    private int age;

    public String getName() {
     
        return name;
    }

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

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }
}
class Student extends Person{
     
    private String school;

    public String getSchool() {
     
        return school;
    }

    public void setSchool(String school) {
     
        this.school = school;
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        Student stu = new Student();
        stu.setName("张三");
        stu.setAge(20);
        stu.setSchool("山东大学");
        System.out.println("姓名:"+stu.getName()+",年龄:"+stu.getAge()+",学校:"+stu.getSchool());

    }
}

执行结果:姓名:张三,年龄:20,学校:山东大学

继承的限制

限制一:Java不允许多重继承,但是允许多层继承

// An highlighted block
错误示例:
class A{
     }
class B{
     }
class C extends  A,B {
     }

// An highlighted block
多层继承
class A{
     }
class B extends  A {
     }
class C extends  B {
     }

限制二:子类在继承父类时,严格来讲会继承父类中的全部操作,但是对于所有私有操作属于隐式继承,而所有的非私有操作属于显式继承。

// An highlighted block
class A{
     
    private String msg;

    public String getMsg() {
     
        return msg;
    }

    public void setMsg(String msg) {
     
        this.msg = msg;
    }
}
class B extends A{
     }
public class Demo {
     
    public static void main(String[] args) {
     
        B b = new B();
        b.setMsg("张三");
        System.out.println(b.getMsg());

    }
}
执行结果:张三

限制三:在子类对象构造前一定会默认调用父类的构造(默认使用无参构造),以保证父类的对象先实例化,子类对象后实例化。

// An highlighted block
class A{
     
    public A() {
     
        System.out.println("A类构造方法");
    }
}
class B extends A{
     
    public B() {
     
        System.out.println("B类构造方法");
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B();
    }
}
执行结果:A类构造方法
		 B类构造方法

上面代码虽然实例化的是子类对象,但是发现它会默认先执行父类构造,调用父类构造的方法体执行,再实例化子类对象并且调用子类的构造方法。对于子类的构造而言,就相当于隐含了super()的语句调用,由于super()主要调用父类的构造方法,所以必须放在子类构造方法的首行。
子类隐含语句

// An highlighted block
class B extends A{
     
    public B() {
     
    	super();	//父类中有无参构造时,加与不加无区别,如果编写则必须出现在首行
        System.out.println("B类构造方法");
    }
}

父类不提供无参构造方法

// An highlighted block
class A{
     
    public A(String title) {
     	//父类提供的有参构造方法
        System.out.println("A类构造方法,title="+title);
    }
}
class B extends A{
     
    public B(String title) {
     	//子类提供有参构造
        super(title);			//明确调用父类构造,否则将出现编译错误
        System.out.println("B类构造方法");
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B("hello");
    }
}
执行结果:A类构造方法,title=hello
		 B类构造方法

覆写

方法的覆写

没有实现方法覆写

// An highlighted block
class A{
     
    public void fun(){
     
        System.out.println("A类中的fun()方法");
    }
}
class B extends A{
     
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B().fun();
    }
}
执行结果:A类中的fun()方法

实现方法覆写

// An highlighted block
class A{
     
    public void fun(){
     
        System.out.println("A类中的fun()方法");
    }
}
class B extends A{
     
    @Override
    public void fun() {
     
        System.out.println("B类中的fun()方法");
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B().fun();
    }
}

执行结果:B类中的fun()方法

定义更多的子类

// An highlighted block
class A{
     
    public void fun(){
     
        System.out.println("A类中的fun()方法");
    }
}
class B extends A{
     
    @Override
    public void fun() {
     
        System.out.println("B类中的fun()方法");
    }
}
class C extends A{
     
    @Override
    public void fun() {
     
        System.out.println("C类中的fun()方法");
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B().fun();
        new C().fun();
    }
}

执行结果:B类中的fun()方法
		 C类中的fun()方法

覆写权限问题:被子类覆写的方法不能拥有比父类更严格的访问控制权限
例如:如果父类的方法是default(默认),那么子类覆写方法时候只能使用default或者public,注意pirvate的方法不能被覆写。

// An highlighted block
class A{
     
     void fun(){
     
        System.out.println("A类中的fun()方法");
    }
}
class B extends A{
     
    @Override
    public void fun() {
     					//此时子类中的方法权限与父类相比更加宽松
        System.out.println("B类中的fun()方法");
    }
}

利用super()方法访问父类中的方法

// An highlighted block
class A{
     
     void fun(){
     
        System.out.println("A类中的fun()方法");
    }
}
class B extends A{
     
    @Override
    void fun() {
     
        super.fun();
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B().fun();

    }
}
执行结果:A类中的fun()方法

属性的覆盖

如果子类定义了和父类完全相同的属性名称时,就称位属性的覆盖。

// An highlighted block
class A{
     
    String info = "hello";
}
class B extends A{
     
    int info = 10;			//名称相同,发生属性覆盖
    void fun() {
     
        System.out.println(super.info);
        System.out.println(this.info);
        System.out.println(info);
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        new B().fun();

    }
}

执行结果:hello
		 10
		 10

注意:在任何开发中,属性一般使用private封装,那么一旦封装后属性覆盖时没有任何意义的,因为父类定义的私有属性子类根本就看不见,更不会相互影响了。

this与super的区别

NO. 区别 this super
1 功能 调用本类构造、本类方法、本类属性 子类调用父类构造、父类方法、父类属性
2 形式 先查找本类中是否存在有指定的调用结果,如果有则直接调用,如果没有则调用父类定义 不查找子类,直接调用父类操作
3 特殊 表示本类的当前对象

在开发中,对于本类或父类中的操作,强烈建议加上“this.”或者“super.”的标记,便于维护。

继承案例

开发数组的父类

// An highlighted block
class Array{
     
    private int data[];
    private int foot;
    public Array(int len) {
     
        if(len > 0){
     
            this.data = new int[len];
        }else {
     
            this.data = new int[1];
        }
    }
    public boolean add(int num){
     
        if(this.foot < this.data.length){
     
            this.data[this.foot++] = num;		//this.foot++的值为0
            return true;
        }
        return false;
    }
    public int[] getData(){
     
        return this.data;
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        Array arr = new Array(3);
        System.out.println(arr.add(20)+"、");
        System.out.println(arr.add(10)+"、");
        System.out.println(arr.add(30)+"、");
        System.out.println(arr.add(100)+"、");	//不可以保存数据,返回false
        int [] temp = arr.getData();
        for(int x = 0; x < temp.length; x++){
     
            System.out.print(temp[x]+"、");
        }
    }
}
执行结果:truetruetruefalse201030

提示:以上代码存在缺陷,存粹只是举个例子而已。
问:i++和++i的区别

// An highlighted block
public class Message {
     
    static int num ;		//初始值为0
    static int sum;			//初始值为0
    public static void main(String[] args) {
     
        System.out.println("sum = num++:"+num++);
        System.out.println(num);
        System.out.println("sum = ++num:"+(++num));
        System.out.println(num);
    }
}
执行结果:sum = num++:0
		  1
		 sum = ++num:2
		  2

由以上结果可以看出:sum = num++ 此时 sum = num(也就是0),然后num会自加1(也就是num为1)。sum = ++num ,此时,num会先自加1(也就是num 为 1),然后sum 为num自加之后的值,也就是1.

开发排序类

// An highlighted block
class SortArray extends Array{
     
    public SortArray(int len){
     
        super(len);
    }
    public int[] getData(){
     
        java.util.Arrays.sort(super.getData());
        return super.getData();
    }
}
public class Demo {
     
    public static void main(String[] args) {
     
        SortArray arr = new SortArray(3);
        System.out.println(arr.add(20)+"、");
        System.out.println(arr.add(10)+"、");
        System.out.println(arr.add(30)+"、");
        System.out.println(arr.add(100)+"、");	//不可以保存数据,返回false
        int [] temp = arr.getData();
        for(int x = 0; x < temp.length; x++){
     
            System.out.print(temp[x]+"、");
        }
    }
}
执行结果:truetruetruefalse102030

开发反转类

反转类指的是进行数组数据取得时,可以实现数据的首尾交换。

// An highlighted block
class ReverseArray extends Array{
     
    public ReverseArray(int len){
     
        super(len);
    }
    public void  reverse(){
     
        int center = super.getData().length/2;
        int head = 0;
        int tail =super.getData().length-1;
        for(int i = 0; i < center; i++) {
     
            int temp = super.getData()[tail];
            super.getData()[tail] = super.getData()[head];
            super.getData()[head] = temp;
            head++;
            tail--;
        }
    }

    @Override
    public int[] getData() {
     
        return super.getData();
    }
}
public class Message {
     
    public static void main(String[] args) {
     
        ReverseArray reverseArray = new ReverseArray(5);
        reverseArray.add(10);
        reverseArray.add(20);
        reverseArray.add(30);
        reverseArray.add(40);
        reverseArray.add(50);
        reverseArray.reverse();
        for(int i = 0 ; i < reverseArray.getData().length ; i++) {
     
            System.out.println(reverseArray.getData()[i]);
        }
    }
}
执行结果:5040302010

final关键字

在Java中final称为终结器,可以使用final定义类、方法和属性。

  • 使用final定义的类不能再有子类,即:任何类都不能继承以final声明的父类。
// An highlighted block
final class A{
     			//此类不能够有子类
}
class B extends A{
     		//错误继承
}
  • 使用final定义的方法不能被子类所覆写
// An highlighted block
class A{
     			
	public final void fun(){
     }		//此方法不允许子类覆写
}
class B extends A{
     		
	public void fun(){
     }		//此处不允许覆写
}
  • 使用final定义的变量就成了常量,常量必须在定义的时候设置好内容,并且不能修改。
// An highlighted block
class A{
     			
   final double AA = 10.1;
   public final void fun(){
     
   	AA = 1.1;				//不能修改常量
   }		
}

全局常量指的是利用了public static final 这3个关键字联合定义的常量。例如:public static final String MSG = “hello”;
需要记住的是,在定义常量时必须对其进行初始化赋值,否则将出现语法错误。

多态性

  • 方法的多态性:重载与覆写;
    重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能;
    覆写:同一个方法,根据实例化的子类对象不同,所完成的功能也不同。

  • 对象的多态性:父子类对象的转换。
    向上转型:子类对象变为父类对象,格式:父类 父类对象 = 子类实例,自动转换;
    向下转换:父类对象变为子类对象,格式:子类 子类对象 = (子类)父类实例,强制转换;

// An highlighted block
class A{
     
    public void print(){
     
        System.out.println("A");
    }
}
class B extends A{
     
    @Override
    public void print() {
     
        System.out.println("B");
    }
}
public class TestDemo {
     
    public static void main(String[] args) {
     
        B b = new B();
        b.print();
    }
}
执行结果:B

B对象自动向上转型

// An highlighted block
public class TestDemo {
     
    public static void main(String[] args) {
     
        A a = new B();		//实例化的是子类对象,对象向上转型
        a.print();			
    }
}
执行结果:B

向上转型特点:不要看类名称,而要看实例化对象的类。

对象向下转型

// An highlighted block
public class TestDemo {
     
    public static void main(String[] args) {
     
        A a = new B();		//实例化的是子类对象,对象向上转型
        B b = (B)a;			//对象需要强制性地向下转型
        b.print();
    }
}
执行结果:B

因为有强制性转换的操作,所以向下转型操作本身是有前提条件的,即必须发生向上转型后才可以发生向下转型。

错误的向下转型

// An highlighted block
public class TestDemo {
     
    public static void main(String[] args) {
     
        A a = new A();
        B b = (B)a;
        a.print();
    }
}
执行结果:Exception in thread "main" java.lang.ClassCastException: A cannot be cast to B at TestDemo.main(TestDemo.java:16)

如果两个没有关系的类对象强制发生向下转型时会带来类转换异常。所以向下转型是会存在安全隐患的,应尽量避免。

向上转型作用分析

// An highlighted block
class A{
     
    public void print(){
     
        System.out.println("A");
    }
}
class B extends A{
     
    @Override
    public void print() {
     
        System.out.println("B");
    }
}
class C extends A{
     
    @Override
    public void print() {
     
        System.out.println("C");
    }
}
public class TestDemo {
     
    public static void main(String[] args) {
     
        A a1 = new B();
        A a2 = new C();
        fun(a1);
        fun(a2);
    }
    public static void fun(A a){
     		//方法中参数类型只能是一个可以包含B类和C类的的统一类型
        a.print();
    }
}
执行结果:BC

由以上可知,向上转型的主要目的是统一调用的参数类型。

向下转型,调用子类中的特殊功能

// An highlighted block
class A{
     
    public void print(){
     
        System.out.println("A");
    }
}
class B extends A{
     
    @Override
    public void print() {
     
        System.out.println("B");
    }
    public void msg(){
     
        System.out.println("B类中的扩充方法");
    }
}
public class TestDemo {
     
    public static void main(String[] args) {
     
        A a = new B();
        fun(a);
    }
    static void fun(A a){
     
        B b = (B)a;
        b.msg();
    }
}
执行结果:B类中的扩充方法

instanceof关键字
instanceof关键字可以判断某一个对象是否是指定类的实例。

// An highlighted block
对象 instanceof 类	返回boolean 型 		//是返回true,否则返回false



public class TestDemo {
     
    public static void main(String[] args) {
     
        A a = new B();      //对象向上转型
        System.out.println(a instanceof A);
        System.out.println(a instanceof B);
        System.out.println(null instanceof A);
    }
}
执行结果:true
		 true
		 false

向下转型时建议使用instanceof判断下

// An highlighted block
class A{
     
    public void print(){
     
        System.out.println("A");
    }
}
class B extends A{
     
    @Override
    public void print() {
     
        System.out.println("B");
    }
    public void msg(){
     
        System.out.println("B类中的扩充方法");
    }
}
public class TestDemo {
     
    public static void main(String[] args) {
     
        A a = new B();      //对象向上转型
        fun(a);
    }
    static void fun(A a){
     
        if(a instanceof B){
     
            B b = (B)a;
            b.msg();
        }
    }
}
执行结果:B类中的扩充方法

抽象类

抽象类定义

抽象类就是指在普通类的结构里面增加抽象方法的组成部分,抽象方法指的是没有方法体的方法,同时抽象方法还必须使用abstract关键字进行定义。。拥有抽象方法的类一定属于抽象类,抽象类要使用abstract声明。

定义抽象类

// An highlighted block
abstract class A{
     
    public void print(){
     
        System.out.println("A");
    }
    public abstract void fun();
}

注意:抽象类不能直接实例化对象(因为有抽象方法,但是抽象方法没有方法体,怎么可能去调用?)

使用抽象类,需要遵循一下原则:

  • 抽象类必须有子类,即每一个抽象类一定要被子类所继承,但是在Java中每一个子类只能够继承一个抽象类,所以具备单继承局限;
  • 抽象类的子类(子类不是抽象类)必须覆写抽象类中的全部抽象方法(强制子类覆写);
  • 依靠对象的向上转型概念,可以通过抽象类的子类完成抽象类的实例化对象操作。
// An highlighted block
abstract class A{
     
   public void print(){
     
       System.out.println("A");
   }
   public abstract void fun();
}
class B extends A{
     
   @Override
   public void fun() {
     
       System.out.println("hello");
   }
}

public class TestDemo {
     
   public static void main(String[] args) {
     
       A a = new B();      //对象向上转型
       a.fun();
   }
}
执行结果:hello

抽象类的相关限制

  • 抽象类里面由于会存在一些属性,那么在抽象类中一定会存在构造方法,目的是为了属性初始化,并且子类对象实例化时依然满足先执行父类构造再调用子类构造的情况。
  • 抽象类不能使用final定义,因为抽象类必须有子类,而final定义的类不能有子类
  • 抽象类中可以没有任何抽象方法,但是只要是抽象类,就不能直接使用关键字new实例化对象
// An highlighted block
abstract class A{
     
   public void print(){
     
       System.out.println("A");
   }
}
class B extends A{
     
}

public class TestDemo {
     
   public static void main(String[] args) {
     
       A a = new B();      //对象向上转型
       a.print();
   }
}
执行结果:A
  • 抽象类中依然可以定义内部的抽象类,而实现的子类也可以根据需要选择是否定义内部类来继承抽象内部类
// An highlighted block
abstract class A{
     
   abstract class B{
     
       public abstract void fun();
   }
}
class X extends A{
     
   public void print(){
     
       System.out.println("访问:www.baidu.com");
   }
   class Y extends B{
     
       @Override
       public void fun() {
     
           System.out.println("方法覆写");
       }
   }
}

public class TestDemo {
     
   public static void main(String[] args) {
     
       X x = new X();      
       x.print();
       X.Y xy = x.new Y();
       xy.fun();
   }
}
执行结果:访问:www.baidu.com
   	     方法覆写
  • 外部抽象类不允许使用static声明,而内部的抽象类允许使用static声明,使用static声明的内部抽象类就相当于是一个外部抽象类,继承的时候使用“外部类.内部类”的形式表示类名称。
// An highlighted block
abstract class A{
     
    static abstract class B{
     
        public abstract void fun();
    }
}
class X extends A.B{
     
    @Override
    public void fun() {
     
        System.out.println("访问:www.baidu.com");
    }
}

public class TestDemo {
     
    public static void main(String[] args) {
     
        A.B ab = new X();
        ab.fun();
    }
}
执行结果:访问:www.baidu.com
  • 在抽象类中,如果定义了static属性或方法,就可以在没有对象的时候直接调用
// An highlighted block
abstract class A{
     
    public static void fun(){
     
        System.out.println("访问:www.baidu.com");
    }
}

public class TestDemo {
     
    public static void main(String[] args) {
     
        A.fun();
    }
}
执行结果:访问:www.baidu.com

隐藏抽象类子类

// An highlighted block
abstract class A{
     
    public abstract void print();
    private static class B extends A{
     
        @Override
        public void print() {
     
            System.out.println("访问:www.baidu.com");
        }
    }
    public static A getInstance(){
     
        return new B();
    }
}
public class TestDemo {
     
    public static void main(String args[]){
     
        A a = A.getInstance();
        a.print();
    }
}
执行结果:访问:www.baidu.com

抽象类的应用-模板设计模式

抽象类的最主要特点相当于制约了子类必须覆写的方法,同时抽象类中也可以定义普通方法,而且最为关键的是,这些普通方法定义在抽象类时,可以直接调用类中定义的抽象方法,但是具体的抽象方法内容就必须由子类提供。

// An highlighted block
abstract class A{
     
    public void fun(){
     
        this.print();
    }
    public abstract void print();
}
class B extends A{
     
    @Override
    public void print() {
     
        System.out.println(11);
    }
}
public class TestDemo {
     
    public static void main(String args[]){
     
        A a = new B();
        a.fun();
    }
}
执行结果:11

定义一个行为类

// An highlighted block
abstract class Action{
     
	public static final int EAT = 1;
	public static final int SLEEP = 5;
	public static final int WORK = 7;
	public void command(int flag){
     
		switch(flag){
     
		case EAT:
			this.eat();
			break;
		case SLEEP:
			this.sleep();
			break;
		case WORK:
			this.work();
			break;
		case EAT + WORK:
			this.eat();
			this.work();
			break;
		}
	}
	public abstract void eat();
	public abstract void sleep();
	public abstract void work();
}

定义描述机器人的行为子类

// An highlighted block
class Robot extends Action{
     
	public void eat(){
     
		system.out.println("机器人充电");
	}
	public void sleep(){
     	//此操作不需要但必须覆写,所以方法体为空
	}
	public void work(){
     
		system.out.println("机器人在工作");
	}
}

定义人的类

// An highlighted block
class Human extends Action{
     
	public void eat(){
     
		system.out.println("人在吃饭");
	}
	public void sleep(){
     	
		system.out.println("人在睡觉");
	}
	public void work(){
     
		system.out.println("人在工作");
	}
}

定义猪的类

// An highlighted block
class Pig extends Action{
     
	public void eat(){
     
		system.out.println("猪在吃食物");
	}
	public void sleep(){
     	
		system.out.println("猪在睡觉");
	}
	public void work(){
     
	}
}

测试类

// An highlighted block
public class TestDemo {
     
	public static void main(String args[]){
     
		fun(new Robot());
		fun(new Human());
		fun(new Pig());
	}
	public static void fun(Action act){
     
		act.command(Action.EAT);
		act.command(Action.SLEEP);
		act.command(Action.WORK);
	}
}
执行结果:机器人充电
		 机器人在工作		(省略)...

接口

接口的定义

如果一个类只是由抽象方法和全局常量组成的,那么将其定义为接口。所谓接口就是一个特殊的类,而且这个类里面只有抽象方法和全局常量。
定义接口

// An highlighted block
interface A{
     
	public static final String MSG = "HELLO";
	public abstract void print();
}

接口的简化定义

// An highlighted block
interface A{
     
	String MSG = "HELLO";
	public void fun();
}
  • 接口中存在抽象方法,所以不能直接使用new进行实例化操作
  • 接口必须要有子类,但子类可以使用implements关键字实现多个接口,避免单继承局限
  • 接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法
  • 接口的对象可以利用子类对象的向上转型进行实例化操作

实现接口

// An highlighted block
interface A{
     
	String MSG = "HELLO";
	public void fun();
}
interface B{
     
	public abstract void get();
}
class X implements A,B{
     
	public void fun(){
     
		system.out.println("A接口的抽象方法");
	}
	public void get(){
     
		system.out.println("B接口的抽象方法");
	}
}
public class TestDemo{
     
	public static void main (String args[]){
     
		X x = new X();
		A a = x;
		B b = x;
		a.fun();
		b.get();
		system.out.println(a.MSG)
	}
}
执行结果:A接口的抽象方法
		 B接口的抽象方法
		 HELLO

判断类型

// An highlighted block
interface A{
     
    String MSG = "heelo";
    public void fun ();
}
interface B{
     
    public void get();
}
class X implements A,B{
     
    @Override
    public void fun() {
     
    }
    @Override
    public void get() {
     
        System.out.println("B接口的抽象方法");
    }
}
public class Main {
     

    public static void main(String[] args) {
     
	// write your code here
        A a = new X();
        B b = new X();
        b.get();
        System.out.println(a instanceof A);
        System.out.println(b instanceof B);
    }
}
执行结果:B接口的抽象方法
true
trueru

如果一个子类既要继承抽象类又要实现接口,那么应该采用先继承extends后实现接口implements的顺序完成

// An highlighted block
interface A{
     
    public void fun ();
}
interface B{
     
    public void get();
}
abstract class C{
     
    public abstract void change();
}
class X extends C implements A,B{
     
    @Override
    public void fun() {
     
        System.out.println("A接口的抽象方法");
    }
    @Override
    public void get() {
     
        System.out.println("B接口的抽象方法");
    }
    @Override
    public void change() {
     
        System.out.println("C类的抽象方法");
    }
}

接口的多继承

// An highlighted block
interface A{
     
    public void funA();
}
interface B{
     
    public void funB();
}
interface C extends A,B{
     
    public abstract void funC();
}
class X implements C{
     
    @Override
    public void funA() {
     
        System.out.println("A接口的抽象方法");
    }
    @Override
    public void funB() {
     
        System.out.println("B接口的抽象方法");
    }
    @Override
    public void funC() {
     
        System.out.println("C类的抽象方法");
    }
}

在定义接口C时使用extends关键字继承了两个父接口,这就相当于C接口中一共定义3个抽象方法,所以在定义X子类时必须覆写3个抽象方法。

在接口里面定义抽象类

// An highlighted block
interface A{
     
    public void funA();
    abstract class D{
     
        public abstract void funD();
    }
}
class X implements A{
     
    @Override
    public void funA() {
     
        System.out.println("A接口的抽象方法");
    }
    class Y extends D{
     
        @Override
        public void funD() {
     
            //可以选择性继承
        }
    }
}

如果在一个接口内部使用static去定义一个内部接口,该接口就表示是一个外部接口

// An highlighted block
interface A{
     
    public void funA();
    static interface B{
     
        public void funB();
    }
}
class X implements A.B{
     
    @Override
    public void funB() {
     
        System.out.println("A接口的抽象方法");
    }
}

接口的实际应用-标准

在日常的生活中,人们会经常听到接口这一词,而最常见的就是USB接口。利用USB接口可以连接U盘、电脑等设备。
如果要进行代码开发,一定要首先开发处USB接口标准,因为有了标准后,计算机才可以去使用这些标准,设备厂商才可以设计USB设备。
定义USB标准

interface USB{
     
	public void start();
	public void stop();
}

定义计算机类

class Computer{
     
	public void plugin(USB usb){
     
		usb.start();
		usb.stop();
	}
}

在计算机类中提供一个plugin()方法,这个方法可以接收USB接口实例,这样不管有多少种USB设备(USB接口对应的子类)都可以插入计算机上进行工作。下面依据USB接口标准定义出两个子类。
定义U盘子类

class Flash implements USB{
     
	public void start(){
     
		system.out.println("U盘开始使用");
	}
	public void stop(){
     
		system.out.println("U盘停止使用");
	}
}

定义打印机

class Print implements USB{
     
	public void start(){
     
		system.out.println("打印机开始使用");
	}
	public void stop(){
     
		system.out.println("打印机停止使用");
	}
}

按照上述方式,可以准备几万个子类,并且这几万个子类都可以在电脑的plugin()方法上使用
测试代码

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Computer com = new Computer();
        com.plugin(new Flash());
        com.plugin(new Print()); 
    }
}
结果:U盘开始使用
	 U盘停止使用
	 打印机开始使用
	 打印机停止使用

接口的应用——工厂设计模式(Factory)

interface Fruit{
     
    public void eat();
}

class Apple implements Fruit{
     
    @Override
    public void eat() {
     
        System.out.println("吃苹果");
    }
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Fruit f = new Apple();
        f.eat();
    }
}
结果:吃苹果

上述例子是一个比较熟悉的结构,但是这样的作法真的合理么?
如果要确认一个代码的编写风格是否良好,应该遵循以下两个标准。
1.客户端(现在为主方法main)调用简单,不需要关注具体的细节
2.程序代码的修改,不影响客户端的调用,即使用者可以不去关心代码是否变更。

根据以下2个标准,就可以发现本程序设计上的问题。在取得接口实例化对象时明确地指明了要使用的子类“Fruit f = new Apple()”,如果扩充了子类,客户端就需要去修改。为了解决问题,即想办法让客户端只看见接口而不让其看见子类,就需要一个中间的工具类来取得接口对象。
增加一个工厂类过渡

interface Fruit{
     
    public void eat();
}

class Apple implements Fruit{
     
    @Override
    public void eat() {
     
        System.out.println("吃苹果");
    }
}
class Orange implements Fruit{
     
    @Override
    public void eat() {
     
        System.out.println("吃橙子");
    }
}
class Factory{
     
    public static Fruit getInstance(String className){
     
        if("apple".equals(className)){
     
            return new Apple();
        }else if("orange".equals(className)){
     
            return new Orange();
        }else {
     
            return null;
        }
    }
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Fruit f = Factory.getInstance("orange");
        f.eat();
    }
}
结果:吃橙子

接口的应用——代理设计模式(Proxy)

➢代理设计也是在java开发中使用较多的一种设计模式,所谓的代理设计就是指一个代理主 题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理,就好比在生活中经常使用到的代理上网那样,客户通过网络代理连接网络,由代理服务器完成用户权限,访问限制等与上网操作相关的操作
java基础学习之面向对象高级知识(三)_第1张图片java基础学习之面向对象高级知识(三)_第2张图片
代理设计模式实现

interface Network{
     
    void browse();
}
class Real implements Network{
     
    @Override
    public void browse() {
     
        System.out.println("上网浏览信息");
    }
}
class Proxy implements Network{
     	//代理上网
    private Network network;
    public Proxy(Network network){
     
        this.network = network;
    }
    public void check(){
     
        System.out.println("检查用户是否合法");
    }
    @Override
    public void browse() {
     
        this.check();	//调用其他相关业务操作
        this.network.browse();	//调用真实上网操作
    }
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Network net = null;
        net = new Proxy(new Real());
        net.browse();
    }
}
结果:检查用户是否合法
	上网浏览信息

抽象类与接口的区别

java基础学习之面向对象高级知识(三)_第3张图片

Object类

有一种类是所有类的父类,这就是Object类。

Object类的基本定义

利用Object类来接收对象

class Book{
     
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Object book = new Book();
    }
}

Object类的方法
java基础学习之面向对象高级知识(三)_第4张图片

取得对象信息:toString()

class Book{
     
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Object book = new Book();
        System.out.println(book.toString());
    }
}
结果:Book@4554617c

对象比较:equals()

在Object类,默认的equals()方法比较的是两个对象的内存地址信息,而不是对象内容。

class Book{
     
    private String title;
    private double price;

    public Book(String title, double price) {
     
        this.title = title;
        this.price = price;
    }
    public boolean equals(Object obj){
     		
        if(this == obj){
         //判断是不是自己
            return true;
        }
        if(obj == null){
     
            return false;
        }
        if(!(obj instanceof Book)){
     
            return false;
        }
        Book book = (Book) obj;
        if(this.title.equals(book.title) && this.price == book.price){
     
            return true;
        }
        return false;
    }
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Book book1 = new Book("aa", 79.9);
        Book book2 = new Book("aa", 79.9);
        System.out.println(book1.equals(book2));
    }
}
结果:true

Object类与引用数据类型

➢Object是所有类的父类,那么0bject类可以接收所有类的对象, 但是在Java设计的时候,考虑到引用数据类型的特殊性,所以0bject类实际上是可以接收所有引用数据类型的数据,这就包括了数组、接口、类。
接收数组数据
java基础学习之面向对象高级知识(三)_第5张图片
接收接口对象
Object除了可以接收数组对象外,接口对象也同样可以利用Object接收。
但是要记住,接口不会继承任何类,所以也不会继承Object。
java基础学习之面向对象高级知识(三)_第6张图片

匿名内部类

➢内部类指的是在一个类的内部定义了另外的类结构,利用内部类可以方便的实现私有属性的互相访问,但是内部类是需要明确的使用class进行定义的。而匿名内部类的是没有名字的内部类,但是其必须在抽象类或接口基础上才可以定义。

interface Message{
     
    void fun();     //接口默认使用public,可以不写
}
public class Main {
     
    public static void main(String args[]) throws Exception {
     
        fun(new Message() {
          //使用匿名内部类实例化接口对象
            @Override
            public void fun() {
     
                System.out.println("hello");
            }
        });
    }
    public static void fun(Message msg){
     
        msg.fun();
    }
}
结果:hello

基本数据类型包装类

➢为了方便用户的开发,专门给出了-组包装类, 来包装八种基本数据类型: byte (Byte) 、short (Short) . int (Integer) 、long (Long)、float (Float) 、double (Double)、char (Character) 、boolean boolean (Boolean)
➢但是以上给出的包装类又分为两种子类型:
➢对象型包装类(Object直接子类):Character、Boolean
➢数值型包装类(Number直接子类):Byte、Short、Integer、Long、Float、Double
➢Number是一个抽象类, 里面一共定义了六个操作方法: intValue()、 doubleValue0、 floatValue(、 byteValue0、 shortValue0、 longValue()。

装箱与拆箱操作

➢现在已经存在有基本数据类型与包装类类,那么这两种类型间的转换就通过以下方式定义:
➢装箱操作:将基本数据类型变为包装类的形式;
➢每个包装类的构造方法都可以接收各自数据类型的变量;
➢拆箱操作:从包装类之中取出被包装的数据;
➢利用从Number类中继承而来的一系列: xxxValue()方法完成。

使用int和Integer

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Integer integer = new Integer(10);
        int value = integer.intValue();
        System.out.println(value);
    }
}
结果:10

使用double和Double

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Double aDouble = new Double(10.2);
        double value = aDouble.doubleValue();
        System.out.println(value);
    }
}
结果:10.2

使用boolean和Boolean

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Boolean aBoolean = new Boolean(true);
        boolean value = aBoolean.booleanValue();
        System.out.println(value);
    }
}
结果:true

自动装箱与自动拆箱操作

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        Integer obj = 10;
        int value = obj;
        System.out.println(value);
    }
}
结果:10

数据类型的转换

➢使用包装类最多的情况实际上是它的数据类型转换功能上,在包装类里面提供有将String型数据变为基本数据类型的方法,使用Integer、 Double、 Boolean几个常用类做说明:
➢Integer类: public static int parselnt(String s); .
➢Double类: public static double parseDouble(String s);
➢Boolean类: public static boolean parseBoolean(String s);

将字符串变为int型数据

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        String str = "123";     //字符串需要都是数字
        int i = Integer.parseInt(str);
        System.out.println(i);
    }
}
结果:123

将字符串变为double型数据

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        String str = "10.3";     //字符串需要都是数字
        double i = Double.parseDouble(str);
        System.out.println(i);
    }
}
结果:10.3

将字符串变为boolean型数据

public class Main {
     
    public static void main(String args[]) throws Exception {
     
        String str = "True";     //大小写随便写,不要写错就好
        boolean i = Boolean.parseBoolean(str);
        System.out.println(i);
    }
}
结果:true

你可能感兴趣的:(JavaSE)