2022-03-30

### Javaben get和set方法

#### 开发中封装的简单规则:

- 属性一般使用private 访问权限。

  属性私有后, 提供相应的 get/set 方法来访问相关属性,这些方法通常是public 修饰的,以提供对属性的赋值与读取操作(注意:boolean 变量的get方法是 is 开头!)

  方法:一些只用于本类的辅助性方法可以用 private 修饰,希望其他类调用的方法用public修饰。

  ```java

  package com.company.encapsulation.b;


  //User实现类,Javaben 方法公开,属性私有

  public class User {

      private int id;

      private String name;

      private boolean man;


  //    创建带参构造器


      public User(int id, String name, boolean man) {

          this.id = id;

          this.name = name;

          this.man = man;

      }


      public void printUserInfo(){

          System.out.println(id);

          System.out.println(name);

          System.out.println(man);

      }


      public int getId() {

          return id;

      }


      public void setId(int id) {

          this.id = id;

      }


      public String getName() {

          return name;

      }


      public void setName(String name) {

          this.name = name;

      }


      public boolean isMan() {

          return man;

      }


      public void setMan(boolean man) {

          this.man = man;

      }

  }


  //TestUser测试类

  package com.company.encapsulation.b;


  public class TestUser {

      public static void main(String[] args) {

          User u = new User(100,"xiaoming",true);

          System.out.println(u.getName());

          System.out.println(u.isMan());

      }

  }


  ```

------

### 多态(polymorphism)详解

- 多态定义:

  - 多态指的是同一个方法调用,由于对象不同可能会有不同的行为。现实生活中,同一个方法,具体实现会完全不同。 比如:同样是调用人“吃饭”的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。

- 多态的要点:

  1. 多态是方法的多态,不是属性的多态(多态与属性无关)


  2. 多态的存在要有 3 个必要条件:继承,方法重写,父类引用指向子类对象。


  3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。


    ```java

    //定义Animal类和继承重写shout()方法


    package com.company.polymorphism;


    public class Animal {

        public void shout(){

            System.out.println("叫了一声");

        }

    }


    class Dog extends Animal{

        @Override

        public void shout(){

            System.out.println("汪汪汪!");

        }


        public void seeDoor(){

            System.out.println("看门中...");

        }

    }


    class Cat extends Animal{

        @Override

        public void shout() {

            System.out.println("喵喵喵!");

        }

    }

    ------------------------------------------------------------------------------


    //测试不同对象,调用相同的方法,产生不同行为

    package com.company.polymorphism;


    public class TestAnimal {

        public static void main(String[] args) {

            animalCry(new Dog());

            animalCry(new Cat());

            //编译时类型      运行时类型

            Animal animal = new Dog();

            animal.shout();

    //        animal.seeDoor();

        }


        static void animalCry(Animal a) {    //Animal a = new Dog() 父类引用指向子类对象

            System.out.println("TestAnimal.animalCry");

            a.shout();  //可以出现多态

        }

    }

    ```

- 对象的转型(casting)

  - 父类引用指向子类对象,我们称这个过程为**向上转型**,属于自动类型转换。

  - 向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。

    这时,我们就需要进行类型的强制转换,我们称之为**向下转型**

    ```java

            //编译时类型      运行时类型

            Animal animal = new Dog();  //向上转型(自动)

            animal.shout();

            Dog d = (Dog) animal; //强制向下转型

            d.seeDoor();

    ```

  - 父类引用变量被强制转换成非对应子类对象,编译时不会报错,运行时会报错;

    ```java

            //编译时不会报错,运行时会报错:java.lang.ClassCastException

            Animal animal = new Dog();

            Cat c =  (Cat) animal;

            c.catchMouse();

    ```

    ![image-20220329181206545](面向对象.assets/image-20220329181206545.png)

  - 解决方法:对父类引用变量做类型判断

    ```java

            if(animal instanceof Cat){

                Cat c =  (Cat) animal;

                c.catchMouse();

            }

    ```


### 抽象类和接口

#### 抽象方法和抽象类

- 抽象方法

  1. 使用 abstract 修饰的方法,没有方法体,只有声明。

  1. 定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。

- 抽象类

  1. 包含抽象方法的类就是抽象类。

  2. 通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。

    ```java

    package com.company.abstractClass;


    /**

      * 测试抽象类

      */

    public abstract class Animal {

        int age;

        public abstract void rest();

        public abstract void run();

        public void shout(){

            System.out.println("Animal.shout");

        };

    }


    class Dog extends Animal{

        @Override

        public void rest() {

            System.out.println("Dog.rest");

        }


        @Override

        public void run() {

            System.out.println("Dog.run");

        }

    }

    class Cat extends Animal{

        @Override

        public void rest() {

            System.out.println("Cat.rest");

        }


        @Override

        public void run() {

            System.out.println("Cat.run");

        }

    }

    ```

- 抽象类的使用要点:

  1. 有抽象方法的类只能定义成抽象类;

  1. 抽象类不能实例化,即不能用 new 来实例化抽象类;

  3. 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来 new 实例,

    只能用来被子类调用。

  1. 抽象类只能用来被继承。

  1. 抽象方法必须被子类实现。

### 接口interface

- 定义定义:

  - 接口就是一组规范(就像我们人间的法律一样)所有实现类都要遵守。

  - 面向对象的精髓,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如 C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。

    ![image-20220329183639201](面向对象.assets/image-20220329183639201.png)

  接口的作用

- 为什么需要接口?接口和抽象类的区别?

  - 接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:**规范和具体实现的分离**。

  - 接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。做系统时往往就是使用“面向接口”的思想来设计系统。

  - **接口和实现类不是父子关系,是实现规则的关系**。比如:定义一个接口 Runnable,Car 实现它就能在地上跑,Train 实现它也能在地上跑,飞机实现它也能在地上跑。就是说,如果它是交通工具,就一定能跑,但是一定要实现 Runnable 接口。

如何定义和使用接口

- 声明格式:

  - [访问修饰符] interface 接口名 [extends] 父接口 1,父接口 2{

    常量定义;

    方法定义;

    }

  - 定义接口的详细说明:

    ☐ **访问修饰符:**只能是 public 或默认。

    ☐ **接口名:**和类名采用相同命名机制。

    ☐ **extends:**接口可以多继承。

    ☐ **常量:**接口中的属性只能是常量,总是:public static final 修饰。不写也是。

    ☐ **方法:**接口中的方法只能是:public abstract。省略的话,也是 public abstract。

    ```java

    //定义Volant接口

    package com.company.testInterface;


    //飞行接口

    public interface Volant {

        /*public static final*/ int FLY_HIGHT = 100;


        /*public abstract*/ void fly();

    }


    //善良接口

    interface Honest {

        void helpOther();

    }


    //GoodMan类实现Honest接口

    class GoodMan implements Honest {

        @Override

        public void helpOther() {

            System.out.println("乐于助人");

        }

    }


    //BirdMan类实现Volant接口

    class BirdMan implements Volant {

        @Override

        public void fly() {


        }

    }


    /**

    * 天使实现了多个接口

    */

    class Angel implements Honest, Volant {

        @Override

        public void fly() {

            System.out.println("Angel.fly");

        }


        @Override

        public void helpOther() {

            System.out.println("Angel.helpOther");

        }

    }

    ------------------------------------------------------------------------------


    //测试类创建实例,实现实例的方法

    package com.company.testInterface;


    public class TestVolant {

        public static void main(String[] args) {

            Angel angel = new Angel();

            angel.fly();

            angel.helpOther();

            System.out.println(Volant.FLY_HIGHT);


            Volant volant = new Angel();

            volant.fly();

        }

    }

    ```


- 要点:

  - 类通过 **implements** 来实现接口中的规范。

  -  接口不能创建实例,但是可用于声明引用变量类型。

  - 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是 public 的。

  - JDK1.8(不含8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。

  - **JDK1.8(含8)后,接口中包含普通的静态方法、默认方法。**

- 接口中包含普通的静态方法、默认方法。

  - 默认方法

    - Java 8 及以上新版本,允许给接口添加一个非抽象的方法实现,只需要使用 default 关

      键字即可,这个特征又叫做默认方法(也称为扩展方法);

    - 默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,

      接口可以提供默认方法的实现,所有这个接口的实现类都可以得到默认方法。

      ```java

      package com.company.testInterface;


      /**

      * 测试接口中的新特性(默认方法)

      */

      public interface TestDefault {

          public void printInfo();

          default void moren(){

              System.out.println("测试默认方法");

              System.out.println("TestDefault.moren");

          }

      }


      class TestDefaultClass implements TestDefault{

          @Override

          public void printInfo() {

              System.out.println("TestDefaultClass.printInfo");

          }

      }

      ------------------------------------------------------------------------------

      //创建TestDefaultClass类对象,调用抽象方法printInfo()&默认方法moren();

              TestDefaultClass tfs = new TestDefaultClass();

              tfs.printInfo();

              tfs.moren();

      ```

  - 默认方法

    - JAVA8 以后,我们也可以在接口中直接定义静态方法的实现。 这个静态方法直接从属

      于接口(接口也是类,一种特殊的类),可以通过接口名调用。

      如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类,

      可以通过子类名直接调用。

      ```java

      package com.company.testInterface;


      /**

      * 测试接口中的新特性(默认方法)&静态方法

      */

      public interface TestDefault {

          public void printInfo();


          //默认方法

          default void moren() {

              System.out.println("测试默认方法");

              System.out.println("TestDefault.moren");


      //        普通默认方法调用静态方法,可行

              testStatic();

          }


          //静态方法

          static void testStatic() {

              System.out.println("TestDefault.testStatic");

      //        静态方法不能调用默认方法,不可行

      //        moren();

          }

      }


      class TestDefaultClass implements TestDefault {

          @Override

          public void printInfo() {

              System.out.println("TestDefaultClass.printInfo");

          }


          static void testStatic() {

              System.out.println("TestDefaultClass.testStatic");

          }

      }

      ------------------------------------------------------------------------------


      //接口静态方法测试类

      package com.company.testInterface;


      public class Test {

          public static void main(String[] args) {

              TestDefaultClass tdc = new TestDefaultClass();

              tdc.printInfo();

              //调用默认方法

              tdc.moren();

              //调用从属于接口的静态方法

              TestDefault.testStatic();

              //调用子类的testStatic静态方法

              TestDefaultClass.testStatic();

          }

      }

      ```

### 接口的多继承

- 接口支持多继承,和类的继承类似,子接口 extends 父接口,会获得父接口中的一切。

  ![image-20220330112115349](面向对象.assets/image-20220330112115349.png)

  ```java

  package com.company.testInterface;


  public class TestMultipleInheritance {

      public static void main(String[] args) {

          CImpl c = new CImpl();

          c.testA();

          c.testB();

          c.testC();

      }

  }


  interface A {

      void testA();

  };


  interface B {

      void testB();

  };


  interface C extends A, B {

      void testC();

  };


  class CImpl implements C {


      @Override

      public void testA() {

          System.out.println("CImpl.testA");

      }


      @Override

      public void testB() {

          System.out.println("CImpl.testB");

      }


      @Override

      public void testC() {

          System.out.println("CImpl.testC");

      }

  }

  ```

### 字符串String类详解

- String是最常用的类,要掌握String类常见的方法,它底层实现也需要掌握好,不然在工作开发中很容易犯错。

- String:就是把一堆字符串起来,统一使用。

  - String 类又称作**不可变字符序列**。

  - String 位于 java.lang 包中,Java 程序默认导入 java.lang 包下的所有类。

  - Java 字符串就是**Unicode字符序列**,例如字符串“Java”就是4个Unicode字符'J'、' a'、' v'、' a'组成的。

  - Java 没有内置的字符串类型,而是在标准 Java 类库中提供了一个预定义的类String,每个用双引号括起来的字符串都是 String 类的一个实例。

    ```java

    package com.company.oop;


    public class TestString {

        public static void main(String[] args) {

            String s0 = null;

            String s1 = "";

            String s2 = "java";

            String s3 = new String("java");


            System.out.println(s1.length());

            System.out.println(s2.length());


    //        调用空字符串方法,会报空指针异常

    //        System.out.println(s0.length());

            System.out.println("============字符串相等的问题============");

            String g1 = "hello world";

            String g2 = "hello world";

            String g3 = new String("hello world");

            System.out.println(g1 == g2);

            System.out.println(g1 == g3);

            System.out.println(g1.equals(g3));

        }

    }

    ```

### String类常用的方法

String类是我们最常使用的类。列出常用的方法,请大家熟悉。

>String类的常用方法列表

>

>| 常用方法                                                    | 解释说明                                                    |

>| :----------------------------------------------------------- | :----------------------------------------------------------- |

>| **[charAt](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#charAt-int-)**(int index) | 返回字符串中第index个字符                                    |

>| **[equals](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equals-java.lang.Object-)**([Object](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html) anObject) | 如果字符串与 other 相等,返回true;否则返回false              |

>| **[equalsIgnoreCase](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equalsIgnoreCase-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) anotherString) | 如果字符串与 other 相等(忽略大小写),则返回true,否则返回 false。 |

>| **[indexOf](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#indexOf-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) str) | 返回从头开始查找第一个子字符串 str 在字符串中的索引位置。如果未找到子字符串 str,则返回-1。 |

>| **[lastIndexOf](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#lastIndexOf-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) str) | 返回从末尾开始查找第一个子字符串 str 在字符串中的索引位置。如果未找到子字符串 str,则返回-1。 |

>| **[length](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#length--)**() | 返回字符串的长度                                            |

>| **[replace](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#replace-char-char-)**(char oldChar, char newChar) | 返回一个新串,它是通过用newChar替换此字符串中出现的所有 oldChar 而生成的。 |

>| **[startsWith](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#startsWith-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) prefix) | 如果字符串以prefix开始,则返回true。                        |

>| **[endsWith](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#endsWith-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) suffix) | 如果字符串以prefix结尾,则返回true,                          |

>| **[substring](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#substring-int-)**(int beginIndex) | 返回一个新字符串,该串包含从原始字符串beginlndex到串尾。    |

>| **[substring](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#substring-int-int-)**(int beginIndex, int endIndex) | 返回一个新字符串,该串包含从原始字符串beginlndex到串尾或endIndex-1的所有字符。 |

>| **[toLowerCase](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toLowerCase--)**() | 返回一个新字符串,该串将原始字符串中的所有大写改成小写字母。 |

>| **[toUpperCase](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toUpperCase--)**() | 返回一个新字符串,该串将原始字符串中的所有小写改成大写字母。 |

>| **[trim](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#trim--)**() | 返回一个新字符串,该串删除了原始字符串头部和尾部的空格。    |

>

>

### 内部类

- 我们把一个类放在另一个类的内部定义,称为内部类(inner class)

  ![image-20220330164529828](面向对象.assets/image-20220330164529828.png)

> 内部类的两个要点:

- 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。

- 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。

> 注意

- 内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类.编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。

- 非静态内部类

  - **非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)**

    - 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类

      对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对

      象。

    - 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类

      成员。

    - 非静态内部类不能有静态方法、静态属性和静态初始化块。

    - 成员变量访问要点:

      - 1.内部类属性:this.变量名。

      - 2.外部类属性:外部类名.this.变量名。

    - 内部类的访问

      - 1.外部类中定义内部类:new Inner()。

      - 2.外部类以外的地方使用非静态内部类:Outer.Inner varname new Outer().new Inner()

  - ```java

    /**

    *测试非静态内部类

    */

    package com.company.innerClass;

    //测试内部类的用法

    public class Outer {

        private int age = 10;

        public void show(){

            System.out.println("Outer.show");

            System.out.println(age);

            //外部类中定义内部类:

            Inner i = new Inner();

            System.out.println(i.age);

        }


        public class Inner{

            int age = 20;

            public void show(){

                System.out.println("Innner.show");

                System.out.println(age);

                System.out.println(Outer.this.age);

                Outer.this.show();

            }

        }

    }



    //测试类

    package com.company.innerClass;


    public class TestOuter {

        public static void main(String[] args) {

            Outer o = new Outer();

            //外部类以外的地方使用非静态内部类:Outer.Inner varname = new Outer().new Inner().

            Outer.Inner i = new Outer().new Inner();

            i.show();

        }

    }

    ```

- 静态内部类

  - 定义方式

    static class ClassName{

    //实体

    }

  - 使用要点:

    - 静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。

    - 静态内部类看做外部类的一个静态成员。

    ```java

    package com.company.innerClass;


    /**

    * 测试静态内部类

    */


    class Outer2 {

        private int a= 10;

        private static int b= 20;

    /**

    *相当于外部类的一个静态成员

    */

        static class Inner2{

            public void test(){

    //            System.out.println(a); 静态内部类不能访问外部类的普通成员。

                //静态内部类可以访问外部类的静态成员

                System.out.println(b);

            }

        }

    }


    /**

    * @author lishuai

    */

    public class TestStaticInnerClass{

        public static void main(String[] args) {

            //通过new 外部类名.内部类名()来创建内部类对象

            Outer2.Inner2 i2 = new Outer2.Inner2();

            i2.test();

        }

    }

    ```

- 匿名内部类

  - 适合那种只需要使用一次的类。比如:键盘监听操作等等。在安卓开发、awt、swing开发中常见。

  - 语法

    new 父类构造器(实参类表)\实现接口(){

    //匿名内部类类体!

    }

    ```java

    package com.company.innerClass;


    /**

    * 测试匿名内部类

    */

    public class TestAnonymousInnerClass {


        public void test1(A a) {

            a.run();

        }


        public static void main(String[] args) {

            TestAnonymousInnerClass t = new TestAnonymousInnerClass();

            t.test1(new A() {

                @Override

                public void run() {

                    System.out.println("第一个匿名内部类");

                }

            });

            t.test1(new A() {

                @Override

                public void run() {

                    System.out.println("第二个匿名内部类");

                }

            });

        }

    }


    interface A {

        void run();

    }

    ```


- 局部内部类

  - 定义在方法内部的,作用域只限于本方法,称为局部内部类。

  - 局部内部类在实际开发中应用很少。

    ```java

    package com.company.innerClass;


    /**

    * 测试局部内部类

    */

    class TestLocalInnerClass {

        public void show(){

            //作用域仅限于该方法

            class Inner{

                public void fun(){

                    System.out.println("Inner.show");

                }

            }

          new Inner().fun();

        }


        public static void main(String[] args) {

            TestLocalInnerClass tlic = new TestLocalInnerClass();

            tlic.show();

        }

    }

    ```

你可能感兴趣的:(2022-03-30)