封装、继承、多态-----------java三大特性java
核心:只对须要的类可见,用户无需知道对象内部方法的实现细节,但能够根据对象提供的外部接口(对象名和参数)访问该对象程序员
同时也是为了减小代码冗余安全
特性:app
安全特性;ide
便于使用特性;性能
提供重复性的特性;测试
好处:ui
- 隐藏信息和实现细节
经过控制访问权限能够将不但愿客户端程序员看见的信息隐藏起来(如客户的银行密码须要保密,便须要只对客户开放权限)this
- 实现了专业的分工
将能实现某一特定功能的代码封装成一个单独的类,在程序员须要使用的时候能够随时调用,从而实现了专业的分工code
- 提升对象数据的安全性
private | default | protected | public | |
---|---|---|---|---|
同一个类 | 可用 | 可用 | 可用 | 可用 |
同一个包中的类 | 可用 | 可用 | 可用 | |
子类 | 可用 | 可用 | ||
其余包中的类 | 可用 |
将多个类具备共同特征和行为封装成一个类,实现一次定义,减小代码冗余,实现了代码的复用性
一个拥有本身独特特征的类(子类 扩展类) 继承(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); } }
同一个行为具备多个不一样的表现形式。
封装和继承是多态的表现形式
多态实现的三个充要条件:
- 继承
- 重写父类方法
- 父类引用指向子类对象
此处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(); } }
向上转型会隐藏子类扩展出来的功能
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()); } }
大范围 -----> 小范围 (强制类型转换):把父类说成是子类
向下转型要求:父类必须拥有子类的属性,不能拥有就会出现类型转换异常
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; } } }
组合就是将对象引用置于新类中。
组合也是一种提升代码复用性的方式。
若是你不想让类有更多的扩展功能,你须要记住一句话多用组合,少用继承
组合和继承是有区别的
特征 | 组合 | 继承 |
---|---|---|
关系 | 组合是一种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 + '\'' + '}'; } }
由于接口不能被实例化,故接口中不能有任何构造方法
若是一个事务只有共同行为(功能)而没有共同特征(属性),则用接口定义
接口注重功能,因此接口中只有方法,且默认为抽象方法(即默认是用
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的周长"); } }
耦合:个体相互之间有依赖关系
好处:
- 便于修改
- 业务并行
- 分工协做
- 通用性强(低耦合)
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 的计算功能!"); }}
抽象类约束没有接口严格,抽象类中能够定义 构造方法、抽象方法、普通属性、普通方法、静态属性和静态方法
抽象方法必定要存在于抽象类中,但抽象类中不必定有抽象方法,也能够有具体的方法
抽象类不能建立对象(
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+"苹果!"); } }
在方法区中会独立分配一块空间用来存放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"); } }
最后的,最终的
能够修饰类、属性(全局变量和局部变量)、方法
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; } }