【Java基础入门篇】三、面向对象和JVM底层分析(2)

打印 上一主题 下一主题

主题 843|帖子 843|积分 2529

Java基础入门篇


三、面向对象和JVM底层分析

3.4 面向对象的三大特征

面相对象的三大特征:封转继承多态
(一)封装

“封装”(encapsulation),封装的理念是高内聚,低耦合


  • “高内聚”:封装细节,便于修改内部代码,提高代码可维护性
  • “低耦合”:简化外部调用,便于使用者使用,便于扩展和协作
封装的优点:提高代码的安全性,提高代码的复用性
封装的实现——使用访问控制符,Java是使用“访问控制符”来控制哪些细节须要封装,哪些细节须要袒露。Java中的访问控制符:private、default、protected、public,访问权限:


  • private(同一个类可用————类内友好)
  • default(不定义默认就是default,同一个类、同一个包可用————包内友好)
  • protected(同一个类、同一个包、子类可用————父子友好、包内友好)
  • public(同一个类、同一个包、子类、所有类可用————全局友好)
若protected——若父类和子类“在同一个包中”,子类可以访问父类的protected成员,也可以访问父类new创建对象的protected成员。若protected——若父类和子类“不在同一个包中”,子类可以访问父类的protected成员,不可以访问父类new创建对象的protected成员。
  1. package BasicJava.encapsulation.a;
  2. /*
  3. *   测试封装
  4. */
  5. public class Person {
  6.     private int testPrivate;
  7.     int testDefault;
  8.     protected int testProtected;
  9.     public int testPublic;
  10.     public void test(){
  11.         System.out.println(this.testPrivate);
  12.     }
  13. }
复制代码
  1. package BasicJava.encapsulation.a;
  2. /*
  3. *   测试封装
  4. */
  5. // 同一个包内的不同类
  6. public class Student {
  7.     public void study(){
  8.         Person p = new Person();
  9.         // System.out.println(p.testPrivate); // 无权访问
  10.         System.out.println(p.testDefault);
  11.         System.out.println(p.testProtected);
  12.         System.out.println(p.testPublic);
  13.     }
  14. }
  15. // 同一个包内具有继承关系的类
  16. class Student2 extends Person{
  17.     public void study(){
  18.         Person p = new Person();
  19.         // System.out.println(p.testPrivate); // 无权访问
  20.         System.out.println(p.testDefault);
  21.         System.out.println(p.testProtected);
  22.         System.out.println(p.testPublic);
  23.     }
  24. }
复制代码
开发过程中封装的简单规则:

  • 属性一般使用private,私有后提供相应的get/set方法来访问相干属性,这些方法通常是public修饰的(注意:boolean变量的get方法是is开头的)。
  • 方法:一些只用于本类的辅助方法可以用private修饰,盼望其他类调用的方法可以用public修饰。
  1. package BasicJava.encapsulation.b;
  2. import BasicJava.encapsulation.a.Person;
  3. /*
  4. *   测试封装
  5. */
  6. public class Child extends Person {
  7.     public void play(){
  8.         Person p = new Person();
  9.         // 此时由于是不同包的继承,所以不能使用父类对象的protected修饰的属性/方法
  10.         //System.out.println(p.testProtected);
  11.         System.out.println(super.testProtected); // 但是可以访问父类的protected成员
  12.     }
  13. }
复制代码
  1. package BasicJava.encapsulation.b;
  2. /*
  3. *   测试封装的简单规则
  4. */
  5. public class User {
  6.     private int id;
  7.     private String name;
  8.     private boolean man;
  9.     // private类型的属性通过get/set方法调用
  10.     public int getId() {
  11.         return id;
  12.     }
  13.     public void setId(int id) {
  14.         this.id = id;
  15.     }
  16.     public String getName() {
  17.         return name;
  18.     }
  19.     public void setName(String name) {
  20.         this.name = name;
  21.     }
  22.     public boolean isMan() {
  23.         return man;
  24.     }
  25.     public void setMan(boolean man) {
  26.         this.man = man;
  27.     }
  28. }
复制代码
  1. package BasicJava.encapsulation.b;
  2. /*
  3. *   测试封装的简单规则
  4. */
  5. public class TestUser {
  6.     public static void main(String[] args) {
  7.         User u = new User();
  8.         u.setId(100);
  9.         u.setName("小明");
  10.         u.setMan(true);
  11.         System.out.println(u.getId());
  12.         System.out.println(u.getName());
  13.         System.out.println(u.isMan());
  14.     }
  15. }
复制代码

(二)继承

当我们不表现指定extends时,默认继承自父类java.lang.Object类,继承的作用:

  • 代码复用,更加容易实现类的扩展,
  • 方便建模,子类是父类的扩展
instanceof运算符是二元运算法,左边是对象,右边是类,用于判定当前对象是否是右边类或子类所创建的对象,是则返回true,反之返回false。
继承中父类又叫超类、基类,子类又叫派生类。Java中只有单继承,不像C++存在多继承,多继承会使得继承链过于复杂,系统难以维护引起紊乱。Java中类没有多继承但是接口有多继承,子类继承父类,可以得到父类全部的属性和方法(除了父类的构造方法),但是不见得可以直接访问,比方父类中的私有属性/方法。
  1. /*
  2.     *   测试继承
  3.      */
  4.     public static class Person{
  5.         String name;
  6.         int height;
  7.         public void rest(){
  8.             System.out.println("休息一会!");
  9.         }
  10.     }
  11.     public static class Student extends Person{
  12.         String school;
  13.         public Student(String name, int height, String school){
  14.             this.name = name;
  15.             this.height = height;
  16.             this.school = school;
  17.         }
  18.         public void study(){
  19.             System.out.println("学习!");
  20.         }
  21.     }
  22.     public static void testExtends(){
  23.         Student s1 = new Student("小明", 175, "HBU");
  24.         s1.study();
  25.         s1.rest();
  26.         System.out.println(s1 instanceof Student);
  27.         System.out.println(s1 instanceof Person);
  28.     }
复制代码

super可以看作是堆父类对象的直接引用,可以通过super来访问父类中被子类覆盖的方法/属性。使用super调用普通方法,语句没有位置限定,可以在子类中任意使用。在一个类中,假如构造方法第一行没有调用super(…)大概this(…),那么Java默认调用super(),含义是调用父类的无参构造方法。
  1. /*
  2. *   使用super调用父类方法
  3. */
  4. public static class FatherClass{
  5.     int value;
  6.     void f(){
  7.         value = 100;
  8.         System.out.println("FatherClass's value is : " + value);
  9.     }
  10. }
  11. public static class ChildClass extends FatherClass{
  12.     int value;
  13.     int age;
  14.     void f(){
  15.         // 调用父类的普通方法
  16.         super.f();
  17.         value = 200;
  18.         System.out.println("ChildClass's value is : " + value);
  19.         System.out.println(super.value);
  20.     }
  21. }
  22. public static void testSuper(){
  23.     ChildClass c1 = new ChildClass();
  24.     c1.f();
  25. }
  26. }
复制代码

方法重写override与方法重载overload毫无关系。重写是指子类重写父类的方法可以用自身的举动替换父类的举动,重写是实现“多态”的须要条件。方法重写须要符合以下三个要点:

  • “==”方法名、形参列表相同
  • “≤”返回值类型和声明非常类型,子类小于等于父类
  • “≥”访问权限,子类大于等于父类
除了继承,**“组合”**也可以实当代码的复用,组合的核心是将父类对象作为子类的属性。组合就是在子类中new一个父类对象,然后通过对象名+属性/方法的方式使用父类。和继承相比,组合更加灵活,继承只能有一个父类,但是组合可以new多个类,使用他们的属性。对于is-a的关系建议使用“继承”(Student is a Person),对于has-a的关系建议使用“组合”(Student has a bike)。
  1. /*
  2.     *   测试方法重写override
  3.      */
  4.     public static  class Vehicle{
  5.         public void run(){
  6.             System.out.println("跑!");
  7.         }
  8.         public Vehicle getVehicle(){
  9.             System.out.println("给你一个交通工具!");
  10.             return null;
  11.         }
  12.     }
  13.     public static class Horse extends Vehicle{
  14.         @Override
  15.         public void run() {
  16.             System.out.println("这是一匹马跑起来了!");
  17.         }
  18.         @Override
  19.         public Horse getVehicle() {
  20.             return new Horse();
  21.         }
  22.     }
  23.     public static void testOverride(){
  24.         Horse h = new Horse();
  25.         h.run();
  26.         h.getVehicle();
  27.     }
复制代码

  1. /*
  2.     *   实现组合
  3.      */
  4.     public static class Car{
  5.         String name;
  6.         int number;
  7.         Car(){
  8.             System.out.println("还没初始化");
  9.         }
  10.         Car(String name, int number){
  11.             this.name = name;
  12.             this.number = number;
  13.         }
  14.         public void run(){
  15.             System.out.println(this.name + this.number + "出发!");
  16.         }
  17.     }
  18.     public static class Bike{
  19.         // 组合就是在子类中new一个父类对象,然后通过对象名+属性/方法的方式使用父类
  20.         Car c = new Car();
  21.         int wheel;
  22.         public Bike(int wheel, String name, int number){
  23.             this.wheel = wheel;
  24.             this.c.name = name;
  25.             this.c.number = number;
  26.         }
  27.         public void letCarGo(){
  28.             System.out.println(this.c.name + this.c.number + "出发!");
  29.         }
  30.         public void letBikeGo(){
  31.             System.out.println("这是一个"+ this.wheel + "轮车,出发!");
  32.         }
  33.     }
  34.     public static void testCombine(){
  35.         Car c1 = new Car("奔驰", 1001);
  36.         c1.run();
  37.         Bike b1 = new Bike(3, "丰田", 1002);
  38.         b1.letCarGo();
  39.         b1.letBikeGo();
  40.     }
复制代码

属性/方法查找顺序,比方,查找变量h -> 查找当前类中有没有属性h -> 依次上溯每个父类 -> 查找每个父类中是否有h,直到Object -> 假如没有找到,则出现编译错误。
构造方法调用顺序,构造方法第一句总是super(…)来调用父类对应的构造方法,流程是:征象上追溯到Object类 -> 然后再次依次向下执行类的初始化块和构造方法 -> 直到当前子类为止。
静态初始化块的执行顺序和构造方法调用顺序一致。
  1. /*
  2. *   感受构造函数初始化顺序
  3. */
  4. class FatherClass2{
  5.     //定义静态初始化块
  6.     static{
  7.         System.out.println("静态初始化块:FatherClass2");
  8.     }
  9.     // 无参构造器
  10.     FatherClass2(){
  11.         System.out.println("创建FatherClass2");
  12.     }
  13. }
  14. class ChildClass2 extends FatherClass2{
  15.     //定义静态初始化块
  16.     static{
  17.         System.out.println("静态初始化块:ChildClass2");
  18.     }
  19.     ChildClass2(){
  20.         // 默认情况下是调用父类的无参构造器,等同于super();
  21.         System.out.println("创建ChildClass2");
  22.     }
  23. }
复制代码

(三)多态

“多态”(polymorphism):同一个方法调用,不同对象举动完全不同
多态的要点:

  • 多态是方法的多态,与属性无关
  • 多态的存在要有三个须要条件(继承、方法重写、父类引用指向子类对象)
  • 父类引用指向子类对象后,用该父类引用调用子类重写的方法,就是多态
  1. package BasicJava.polymorphism;
  2. /*
  3. *   测试多态
  4. */
  5. public class Animal {
  6.     public void shout(){
  7.         System.out.println("动物的叫声");
  8.     }
  9. }
  10. class Dog extends Animal{
  11.     @Override
  12.     public void shout() {
  13.         System.out.println("汪汪汪!");
  14.     }
  15.     public void seeDoor(){
  16.         System.out.println("正在看门...");
  17.     }
  18. }
  19. class Cat extends Animal{
  20.     @Override
  21.     public void shout() {
  22.         System.out.println("喵喵喵!");
  23.     }
  24.     public void catchMouse(){
  25.         System.out.println("正在抓老鼠...");
  26.     }
  27. }
复制代码
对象的转型(casting):由父类引用指向子类对象的过程中,我们称之为“向上转型”,属于“自动类型转换”。向上转型后的父类引用变量只能调用它“编译类型”的方法,不能调用它“运行时类型”的方法,这时我们须要进行强制类型转换,我们称之为“向下转型”。
  1. package BasicJava.polymorphism;
  2. public class TestPoly {
  3.     public static void main(String[] args) {
  4.         animalShout(new Dog()); // 相当于Animal a = new Dog(); 属于“向上转型”
  5.         animalShout(new Cat()); // 相当于Animal a = new Cat(); 属于“向上转型”
  6.         // new Dog()是我们真正的类型,Animal animal是我们定义的类型,因此无法执行Dog()类中的seeDoor()方法
  7.         //编译类型       运行时类型
  8.         Animal animal = new Dog();
  9.         animal.shout(); // 可以执行
  10.         // animal.seeDoor(); //无法执行
  11.         // 通过“向下转型”就可以了,这里的d其实就是animal,只不过进行了强制类型转换
  12.         Dog d = (Dog)animal;
  13.         d.seeDoor();
  14.         // 我们可以添加一个判断来避免异常
  15.         if(animal instanceof Dog){
  16.             Dog d2 = (Dog)animal;
  17.             d2.seeDoor();
  18.         }
  19.         if(animal instanceof Cat){
  20.             Cat c2 = (Cat)animal;
  21.             c2.catchMouse();
  22.         }
  23.         // 测试用不同的类进行“向下转型”的强制类型转换
  24.         Cat c = (Cat)animal;
  25.         c.catchMouse(); // 发现并不报错,但是这实际上只是编译时不报错,但是运行的时候会报错的
  26.                         // "ClassCastException: BasicJava.polymorphism.Dog cannot be cast to BasicJava.polymorphism.Cat"
  27.     }
  28.     static  void animalShout(Animal a){
  29.         a.shout();
  30.     }
  31. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

悠扬随风

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表