「Java基础」6、面向对象 进阶

封装、继承、多态、接口、抽象类、static、final
6、面向对象 进阶

封装继承多态-----------java三大特性java

  • 类、接口间关系
    • 类 与 类 之间是:单根继承
    • 类 与 接口 之间是:多实现
    • 接口 与 接口 之间是:多继承

1 - 封装

核心只对须要的类可见用户无需知道对象内部方法的实现细节,但能够根据对象提供的外部接口(对象名和参数)访问该对象程序员

同时也是为了减小代码冗余安全

特性app

​ 安全特性;ide

​ 便于使用特性;性能

​ 提供重复性的特性;测试

好处ui

  1. 隐藏信息和实现细节

经过控制访问权限能够将不但愿客户端程序员看见的信息隐藏起来(如客户的银行密码须要保密,便须要只对客户开放权限)this

  1. 实现了专业的分工

将能实现某一特定功能的代码封装成一个单独的类,在程序员须要使用的时候能够随时调用,从而实现了专业的分工code

  1. 提升对象数据的安全性
  • 若是不使用封装,很容易赋值错误,而且任何人均可以更改,形成信息的不安全
  • 封装之后,设置类的属性为private(关键字),不能使用对象名.属性名的方式直接访问对象的属性,提升了其安全性。
  • 封装时,类的属性private类的方法public

1 - 1 成员的访问权限

  private default protected public
同一个类 可用 可用 可用 可用
同一个包中的类   可用 可用 可用
子类     可用 可用
其余包中的类       可用

2 - 继承(extends)

将多个类具备共同特征和行为封装成一个类,实现一次定义,减小代码冗余,实现了代码复用

一个拥有本身独特特征的类(子类 扩展类) 继承(extends) 拥有共同特征的类(父类 基类)

子类继承父类,拥有父类的属性,于是子类的对象能够给共同属性赋值

java中一个类只能继承一个类(单根继承)

继承是一个很广泛的现象

若是一个类明确指明了继承(extends)自某一个类,则这个类就是他的父类

若是一个类并未经过extends指明继承自某一个类,则这个类继承自Object类(顶级父类---最大的类)

public class Animal { // 父类
    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;
    }
    
    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}
public class Dog extends  Animal{ // 子类
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
    
    @Override
    public String toString() {
        return "Dog{" +
                "type='" + type + '\'' +
                "} " + super.toString();
    }

}
public class Cat extends Animal{
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "address='" + address + '\'' +
                "} " + super.toString();
    }
}
public class Main { // 测试类
    public static void main(String[] args) {
        Cat cat = new Cat();
        // 共同特征(经过继承获取)
        cat.setName("hello KiTi"); 
        cat.setAge(3);
        // 独有特征
        cat.setAddress("北京");
        System.out.println(cat);
        
        Dog dog  = new Dog();
        // 共同特征(经过继承获取)
        dog.setName("旺财");
        dog.setAge(4);
        // 独有特征
        dog.setType("拉布拉多");
        System.out.println(dog);

    }
}

3 - 多态

同一个行为具备多个不一样的表现形式。

封装和继承多态表现形式

多态实现三个充要条件

  1. 继承
  2. 重写父类方法
  3. 父类引用指向子类对象
  • 此处Fruit apple = new Apple();父类的引用指向子类的对象,这即是多态的一种体现(向上转型),由于Apple继承与Fruit并重写了eatFruit(),因此可以表现多种状态的形式。

  • 向上转型小范围 ------> 大范围

    Fruit apple = new Apple();

  • 动态绑定(自动实现的)

    向上转型后,用父类的变量接收子类的对象(Fruit apple = new Apple();),运行时会找父类类型变量(apple)中存放数据的实际类型(Apple()),并执行这个实际类(Apple())中的对应方法(eatFruit()),而不是父类(Fruit)中的方法(eatFruit()),用static修饰能够解决此问题

/**
 * 水果
 */
public class Fruit {
    String fruit; // 

    public String getFruit() {
        return fruit;
    }

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public void eatFruit(){
        System.out.println("吃水果!");
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "fruit='" + fruit + '\'' +
                '}';
    }
}
/**
 * 苹果
 */
class Apple extends Fruit{

    private String color;   // 颜色

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                "} " + super.toString();
    }

    @Override
    public void eatFruit(){
        color = "红色";
        super.fruit = "苹果";
        System.out.println("吃" + color + fruit);
    }

}
/**
 * 橙子
 */
class Orange extends Fruit{
    private String exterior;   // 外观

    public String getExterior() {
        return exterior;
    }

    public void setExterior(String exterior) {
        this.exterior = exterior;
    }

    @Override
    public void eatFruit() {
        exterior = "圆的";
        super.fruit = "橘子";
        System.out.println("吃" + exterior + fruit);
    }

    @Override
    public String toString() {
        return "Orange{" +
                "exterior='" + exterior + '\'' +
                "} " + super.toString();
    }
}

3 - 1 向上转型的应用场景

向上转型会隐藏子类扩展出来的功能

public class Test {
    // 将参数列表改成各类水果的父类,只须要定义一次,就能够重复利用,而不须要利用方法重写来实现同一个动做
    public static void DoThing(Fruit fruit){
        System.out.println("---------------------------------------");
        fruit.eatFruit();
        System.out.println("---------------------------------------");
    }
//--------------------方法重写,会致使代码冗余--------------------
    /*public static void DoThing(Orange orange){
        System.out.println("---------------------------------------");
        fruit.eatFruit();
        System.out.println("---------------------------------------");
    }
    public static void DoThing(Apple apple){
        System.out.println("---------------------------------------");
        fruit.eatFruit();
        System.out.println("---------------------------------------");
    }*/
//--------------------------------------------------------------

    }

    public static void main(String[] args) {

        DoThing(new Apple());
        DoThing(new Orange());

    }
}

3 - 2 向下转型

大范围 -----> 小范围 (强制类型转换):把父类说成子类

向下转型要求:父类必须拥有子类的属性不能拥有就会出现类型转换异常

Apple apple = (Apple) new Fruit();

  • 向下转型的应用场景

    明确知道了传入的数据是什么类型,才能进行向下转型

    若是要进行向下转型,必须先向上转型,在向下转型,否则会出错

    public class Test {
        
        public static void main(String[] args) {
            
    //        Apple apple = (Apple) new Fruit(); // 单纯的进行强制类型转换会出现异常
            
            Fruit fruit = DoThing(1);
    
            if (fruit instanceof Orange){
                Orange orange = (Orange) fruit;
                System.out.println(orange);
            }else{
                Apple apple = (Apple) fruit;
                System.out.println(apple);
            }
    
        }
    
        public static Fruit DoThing(int number){
            
            if (number == 0){
                Orange orange = new Orange();
                orange.setFruit("橘子");
                orange.setExterior("圆的");
                return orange;
            }else{
                Apple apple = new Apple();
                apple.setFruit("苹果");
                apple.setColor("红色");
                return apple;
            }
        }
    
    }

4 - 组合

组合就是将对象引用置于新类中。

组合也是一种提升代码复用性的方式。

若是你不想类有更多扩展功能,你须要记住一句话多用组合,少用继承

  • 组合和继承是有区别的

    特征 组合 继承
    关系 组合是一种has - a的关系,能够理解为有一个 继承是一中 is - a 的关系,能够理解为是一个
    耦合性 组合是一种松耦合的关系 继承双方紧耦合
    是否具备多态 组合不具有多态和向上转型 继承是多态的基础,能够向上转型
    时期 组合是运行期绑定 继承是编译期绑定
  • Fruit类引用了Apple类、Orange类,从而调用他们各自的属性和方法

public class Test{
    
    public static void main(String[] args) {
        
        Fruit fruit = new Fruit();
        fruit.setFruit("苹果"); 

        Apple apple = new Apple();
        apple.setColor("红的");
        fruit.setApple(apple);

        Orange orange = new Orange();
        orange.setExterior("圆的");
        fruit.setOrange(orange);

        System.out.println(fruit);
        
    }
}
/**
 * 水果
 */
public class Fruit {
    private String fruit;

    private Apple apple;
    private Orange orange;

    public Apple getApple() {
        return apple;
    }

    public void setApple(Apple apple) {
        this.apple = apple;
    }

    public Orange getOrange() {
        return orange;
    }

    public void setOrange(Orange orange) {
        this.orange = orange;
    }

    public String getFruit() {
        return fruit;
    }

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public void eatFruit(){
        System.out.println("吃水果!");
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "fruit='" + fruit + '\'' +
                ", apple=" + apple +
                ", orange=" + orange +
                '}';
    }
}

/**
 * 苹果
 */
class Apple{

    private String color;   // 颜色

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                '}';
    }
}

/**
 * 橙子
 */
class Orange{
    private String exterior;   // 外观

    public String getExterior() {
        return exterior;
    }

    public void setExterior(String exterior) {
        this.exterior = exterior;
    }


    @Override
    public String toString() {
        return "Orange{" +
                "exterior='" + exterior + '\'' +
                '}';
    }
}

5 - 接口和抽象类

5 - 1 接口(interface)

由于接口不能被实例化,故接口不能有任何构造方法

若是一个事务只有共同行为(功能)没有共同特征(属性),则用接口定义

接口注重功能,因此接口中只有方法,且默认为抽象方法(即默认是用public abstract修饰的)

接口能够多实现(implements)

// 定义接口
public interface Shape { 
    void area();    // 计算面积
    void perimeter();   // 计算周长
}
// 实现接口
public class Circle implements Shape {

    @Override
    public void area() {
        System.out.println("计算Circle的面积");
    }

    @Override
    public void perimeter() {
        System.out.println("计算Circle的周长");
    }
}

5 - 1 - 1 接口实现解耦合

耦合:个体相互之间有依赖关系

好处:

  1. ​ 便于修改
  2. 业务并行
  3. 分工协做
  4. 通用性强(低耦合)
  • 案例:
public class Test {
    public static void main(String[] args) {
        
        Computer computer = new Computer();
        
        computer.setMainBoard("I7 的主板"); // 同一块主板可使用不一样的cpu

        computer.setCpu(new I3());
        computer.getCpu().jiSuan();//调用i3主板的计算功能

        computer.setCpu(new I5());
        computer.getCpu().jiSuan();//i5主板的计算功能

        computer.setCpu(new I7());
        computer.getCpu().jiSuan();//i7主板的计算功能
    }

}
public class Computer {
    private String mainBoard; //主板
    private Cpu cpu; // 至关于电脑预留了一个cpu接口,能够安装任意版本

    public String getMainBoard() {
        return mainBoard;
    }

    public void setMainBoard(String mainBoard) {
        this.mainBoard = mainBoard;
    }

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }


    @Override
    public String toString() {
        return "Computer{" +
                "mainBoard='" + mainBoard + '\'' +
                ", cpu=" + cpu +
                '}';
    }
}
public interface Cpu {    void jiSuan(); // cpu的计算功能}class I3 implements Cpu{    @Override    public void jiSuan() {        System.out.println("I3 Cpu 的计算功能!");    }}class I5 implements Cpu{    @Override    public void jiSuan() {        System.out.println("I5 Cpu 的计算功能!");    }}class I7 implements Cpu{    @Override    public void jiSuan() {        System.out.println("I7 Cpu 的计算功能!");    }}

5 - 2 抽象类(abstract)

抽象类约束没有接口严格,抽象类中能够定义 构造方法、抽象方法、普通属性、普通方法、静态属性和静态方法

抽象方法必定存在于抽象类中,但抽象类中不必定有抽象方法,也能够有具体的方法

抽象类不能建立对象Fruit fruit = new Fruit()会报错)

public abstract class Fruit{ // 父类,此时父类也是抽象类
    private String fruit;
    
    public String getFruit();

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public abstract void eatFruit(); // 抽象方法
}

class Apple extends Fruit{ // 子类
    private String color;
    
	public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
    
    @Override
    public void eatFruit() { // 必需要添加父类中的行为,不然会报错
        System.out.println("吃"+color+"苹果!");
    }
}

6 - static

在方法区中会独立分配一块空间用来存放static修饰的数据,static修饰的东西都会存入其中,而且其中的数据是通用的

java中的关键字-----静态的

能够修饰属性和方法

static用在没有建立对象时调用方法/属性

  • 静态成员变量

    能够修饰全局变量,不能修饰局部变量

    class test{    public static String name = "码农"; // 能够修饰全局变量(类变量)        public void Do{		static String name2 = "码羊"; // 报错,不能修饰局部变量    }    }
  • 静态方法

    可使用类名.方法名调用

    static不能修饰 get方法、set方法、构造方法、抽象方法、类

    同一个类中调用类方法,能够省略类名

    静态方法中 ** 不能访问 非静态方法非静态成员变量**

    public class Circle implements Shape {
    
        private static Double PI = 3.14; // 静态成员变量
        private int r; // 非静态成员变量
    
        // 静态方法
        public static void area2(){
    //        2*PI*r;  // 报错,由于此为静态方法,而r为非静态成员变量
        }
    
        @Override
        public void area() {
            System.out.println(PI*r*r);
        }
    
        @Override
        public void perimeter() {
            System.out.println("计算Circle的周长");
        }
    
    }
  • 静态代码快

    用于类的初始化操做,进而提示程序性能

    静态代码块随着类的加载而执行,所以,不少时候会 只须要 执行一次的初始化操做放在static代码块中进行

    public class StaicBlock {
        static{
        	System.out.println("I'm A static code block");
        }
    }

7 - final

最后的,最终的

能够修饰类、属性(全局变量和局部变量)、方法

  • final修饰类时

    一旦修饰,表示此类不能被继承

    成员变量能够根据须要设定为final

    注意final中的全部成员方法会隐式的指定为final方法

  • final修饰方法时

    修饰方法时,表示此方法不能被子类重写

    只有在明确不但愿此方法被子类重写时才会将其设定为final

  • final修饰变量时

    final没有优先分配的功能,因此必须对其进行赋值(可使用构造代码块对其进行赋值,由于构造代码块会在构造方法前执行,且调用几回构造方法,便加载几回构造代码块

    • 修饰基本数据类型

      表示数据类型的值 不能 被改变

      public class Circle implements Shape {
      
          private static Double PI = 3.14;
          private static final Double PII = 3.14;
      
          public static void main(String[] args) {
              PI = 4.5; // 能够正常修改
      //        PII = 3.5; // 报错
          }
      }
    • 修饰引用数据类型时

      表示对其初始化后便 不能 在指向另外一个对象

      public class Test {
          public static void main(String[] args) {
              final Fruit fruit = new Fruit();
              fruit.setFruit("苹果");
              fruit = null; // 报错:Cannot assign a value to final variable 'fruit'
          }
      }
      
      class Fruit{
          private String fruit;
          
          public String getFruit() {
              return fruit;
          }
      
          public void setFruit(String fruit) {
              this.fruit = fruit;
          }
      }
相关文章
相关标签/搜索