继承(extends)

  • 继承的意思即是对一个内容进行扩展构成一个新的内容。
  • 比如:动物可以继承扩展为哺乳动物和爬行动物;他们的底层都是相同的,但是总有一些不一样的地方。
  • Object类是所有Java类的根基类,也就是所有的Java对象都拥有Object类的属性和方法。

instanceof

  1. instanceof 是二元运算符,左边是对象,右边是类
  2. 当对象是右边类或子类所创建的对象时,返回true,否则false.
    1. // Student类是Person的一个子类
    2. Student s = new Student("zs",190,"c++");
    3. System.out.println(s instanceof Person);
    4. System.out.println(s instanceof Student);

继承使用应注意的要点

  1. 父类也成为超类、基类、派生类等。
  2. Java中只有单继承(但是接口可以多继承)。多继承会引起会乱,是的继承链过于复杂,系统难于维护。
  3. Java中类没有多继承,接口有多继承。
  4. 子类继承父类,可以得到父类所有属性和方法(除了父类的构造方法),但不见得可以直接访问(父类的私有属性和方法)。
  5. 在定义类是没有调用 extends ,则他的父类是: java.lang.Object

方法的重写(override)

  1. 重写的条件
    • 方法名和形参列表必须相同。
    • 返回值类型和声明异常类型,子类小于等于父类。
    • 访问权限,子类大于等于父类。 ```java public class TestOverride { public static void main(String[] args) { Vehicle v1 = new Vehicle(); Vehicle v2 = new Horse(); Vehicle v3 = new Plane(); v1.run(); v2.run(); v3.run(); v2.stop(); v3.stop(); } } class Vehicle { // 交通工具类 public void run() { System.out.println(“跑….”); } public void stop() { System.out.println(“停止不动”); } } class Horse extends Vehicle { // 马也是交通工具 public void run() { // 重写父类方法 System.out.println(“四蹄翻飞,嘚嘚嘚…”); } }

class Plane extends Vehicle { public void run() { // 重写父类方法 System.out.println(“天上飞!”); } public void stop() { System.out.println(“空中不能停,坠毁了!”); } }

  1. 3. 继承的方法在使用的时候,必须new.
  2. 3. new的时候可以使用 `Vehicle v3 = new Plane();` ,但是在后边的对象转型的时候,必须注意(不能转错类型,因为一个父类可能存在多个子类)。
  3. <a name="7f4b0424"></a>
  4. ### 一些基础方法(toString,==,equals)
  5. <a name="aStCJ"></a>
  6. #### toString
  7. 1. Object类中定义了 `public String toString()` 方法,其返回值是String类型的。
  8. 1. Object类中的toString方法是输出:类名+@+16进制的hashcode
  9. 1. 所以在一般使用中toString 方法一般都会被重写。
  10. <a name="f2b4cba0"></a>
  11. #### == 和 equals
  12. 1. `==` 海表比较双方是都夏姑娘同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等则为同一个对象。
  13. 1. `equals` 方法默认就是比较两个对象的hashcode,是同一个类型的引用时返回true。一般我们会重写equals方法。
  14. 1. JDK提供的很多类中都对equals方法进行类重写(重写之后一般都是比较内容值是否相等)。
  15. <a name="829081b9"></a>
  16. ### super关键字和继承树
  17. 1. super时直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
  18. 1. 使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。
  19. 1. super()方法构造函数都会默认调用。
  20. 1. 继承方法使用的时候会向上寻找我们的调用(继承树回溯)。
  21. <a name="6912abd3"></a>
  22. ### 封装
  23. - 提高代码的安全性
  24. - 提高代码的复用性
  25. - “高内聚”:封装细节,便于修改内部代码,提高可维护性。
  26. - “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
  27. <a name="f58e1c18"></a>
  28. #### 访问控制
  29. 1. `private` 表示私有,只有自己类能访问
  30. - 只能在自己的类中使用,其他地方都不能使用
  31. - 使用范围:同一个类(一个类就是一个.java中的一个class
  32. 2. `default` 表示没有修饰符修饰,只有同一个包的类能访问
  33. - 在变量或者方法没有被修饰的情况下默认为 default 的,这样就最大就只能在同一个包中使用
  34. - 使用范围:同一个类,同一个包(一个包就是package中)
  35. 3. `protected` 表示可以被同一个包的类以及其他包中的子类访问(好像不太经常使用)
  36. - 在被 protected 修饰的情况下,变量或者方法就最多被继承它的子类所使用。
  37. - 使用范围:同一个类,同一个包,它的子类(使用 extends 继承了它的子类,这儿的继承也就只能在同一个)
  38. 4. `public` 表示可以被该项目的所有包中的所有类访问
  39. <a name="99962c65"></a>
  40. #### 封装的细节
  41. 1. 一般使用 `private` 访问权限
  42. 1. 提供相应的 get/set 方法来访问相关属性,这些方法通常是public的。
  43. 1. boolean 变量的 get 方法是 is 开头的。
  44. 1. 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。
  45. <a name="fd37f62b"></a>
  46. ### 多态(polymorphism)
  47. 1. 多态是方法的多态,不是属性的多态
  48. 1. 多态的存在有三个必要条件:继承,方法重写,父类引用指向子类对象。
  49. 1. 父类引用指向子类对象后,该父类引用调用子类重写的方法,此时多态就出现了。
  50. 1. 简单来说,多态就是多个子类继承同一个父类,然后对父类中的某个方法都进行了重写(override)。这样就构成了多态。
  51. ```java
  52. // 有了多态,只需要让增加的这个类继承Animal类就可以了。
  53. static void animalCry(Animal a) {
  54. a.shout();
  55. }
  1. 不管是什么动物叫,我们只要把对象传进去,就能发出准确的叫声。

对象的转型(casting)

  1. 父类引用指向子类对象,我们成这个过程为向上转型,属于自动类型转换。
  2. 向上转型后的父类引用变量只能调用他编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要强制转型,称之为向下转型。
  3. 类型转换时应该注意异常的处理。

final关键字

  1. final修饰的变量不能被二次赋值。
  2. final修饰的方法,不能被重写。
  3. final修饰的类不能被继承。

抽象方法和抽象类(abstract)

抽象方法

  • 使用abstract修饰的方法,没有方法体,只有声明。
  • 定义的是一种规范,告诉子类必须要给抽象方法提供具体的实现。

抽象类

  • 包含抽象方法的类就是抽象类。
  • 通过abstract方法定义规范,然后要求子类必须定义具体实现
  • 通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。

抽象类使用要求

  1. 抽象方法的类只能定义成抽象类。
  2. 抽象类不能实例化,也就是不能用 new 来实例化抽象类。
  3. 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来 new 实例,只能用来被子类调用。
  4. 抽象类只能用来被继承。
  5. 抽象方法必须被子类实现。

接口(interface)

  • 普通类:具体实现
  • 抽象类:具体实现,规范(抽象方法)。
  • 接口:规范

接口的定义

  1. 声明格式:

    [访问修饰符]  interface 接口名   [extends  父接口1,父接口2…]  {
    常量定义;  
    方法定义;
    }
    
  2. 访问修饰符:只能时public或者默认(default)。

  3. 接口名:和类名采用相同的命名机制;首字母大写和驼峰原则;
  4. extends:接口可以多继承,但是 继承的都是接口
  5. 常量:接口中的属性只能是常量,总是 public static final 修饰的,不写也是如此。
  6. 方法:接口中的方法只能是 public abstract ,省略的话也是 public abstract ,也就意味着方法是抽象的,只需要规范即可,不需要实现。

接口的使用

  1. 子类通过 implements 来实现接口中的规范。
  2. 接口不能创建实例,但是可用于声明引用变量类型。
  3. 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是 public 的。
  4. 在JDK1.8后,接口中包含了静态常量,抽象方法,静态方法。不能有普通属性,构造方法。

    public class TestInterface {
     public static void main(String[] args) {
         Volant volant = new Angel();
         volant.fly();
         System.out.println(Volant.FLY_HIGHT);
    
         Honest honest = new GoodMan();
         honest.helpOther();
     }
    }
    /**飞行接口*/
    interface Volant { 
     int FLY_HIGHT = 100;  // 总是:public static final类型的;
     void fly();   //总是:public abstract void fly();
    }
    /**善良接口*/
    interface Honest { 
     void helpOther();
    }
    /**Angle类实现飞行接口和善良接口*/
    class Angel implements Volant, Honest{
     public void fly() {
         System.out.println("我是天使,飞起来啦!");
     }
     public void helpOther() {
         System.out.println("扶老奶奶过马路!");
     }
    }
    class GoodMan implements Honest {
    public void helpOther() {
         System.out.println("扶老奶奶过马路!");
     }  
    }
    class BirdMan implements Volant {
     public void fly() {
         System.out.println("我是鸟人,正在飞!");
     }
    }
    

接口的多继承

interface A {
    void testa();
}
interface B {
    void testb();
}
/**接口可以多继承:接口C继承接口A和B*/
interface C extends A, B {
    void testc();
}
public class Test implements C {
    public void testc() {
    }
    public void testa() {
    }
    public void testb() {
    }
}

内部类

非静态/静态内部类

public class TestInnerClass {
    public static void main(String[] args) {
        Outer outer = new Outer();
        /**
         * 上边是创建外部类
         * 下边创建内部类
         *
         * 非静态内部类可以直接访问外部类成员,但是外部类不能访问非静态内部类的成员
         * 非静态内部类不能有静态方法、静态属性和静态初始化块。
         * 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
         */

        // 创建非静态内部类
        Outer.Inner inner = new Outer().new Inner();
        inner.show();

        // 创建静态内部类,静态内部类不依托于外部类
        Outer2.Inner2 inner = new Outer.Inner2();
    }
}
class Outer {
    private int age = 10;

    public void testOuter() {
        System.out.println("Outer.testOuter");
    }

    class Inner {
        int age = 20;
        public void show() {
            int age = 30;
            System.out.println("外部类的成员变量age:" + Outer.this.age);
            System.out.println("内部类的成员变量age:" + this.age);
            System.out.println("局部变量age:" + age);
        }
    }
    static class Inner2{
    }
}

匿名内部类

  1. 语法: new 父类构造器(实参类表)\实现接口 () { 匿名内部类类体 }
  2. 匿名内部类只使用一次。

    public class TestAnnonymousInnerClass {
    
     public static void test01(A a){
         System.out.println("ajd");
         a.aa();
     }
     public static void main(String[] args) {
         TestAnnonymousInnerClass.test01(new A() {
             @Override
             public void aa() {
                 System.out.println("Test");
             }
         });
     }
    }
    interface A{
     void aa();
    }
    

String 基础

String类是不可变字符串,方法在之前写了。

String常用方法

image.png

常量池

全局字符串常量池(String Pool)

存放的内容是类加载完成后存到String Pool中的,每个VM只有一份,存放的是字符串常量的引用值。

class文件常量池(Class Constant Pool)

class常量池是在编译的时候每个class都有的,在编译阶段存放的是常量(文本字符串、final常量等)和符号的引用。

运行时常量池(Runtime Constant Pool)

运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。