Java教程

尚硅谷Java入门笔记 - P174 ~ P363

本文主要是介绍尚硅谷Java入门笔记 - P174 ~ P363,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Day07-Day15

目录
  • Day07-Day15
    • 前言
    • 1. 类(Class)
      • 类的组成部分
        • 1.1 属性(成员变量)
        • 1.2 构造器
        • 1.3 代码块
        • 1.4 方法
        • 1.5 内部类
        • 1.6 其它事项
    • 2. 对象
      • 2.1 封装性
      • 2.2 继承性
      • 2.3 多态性
      • 2.4 其它事项
    • 3. 关键字
      • 3.1 this关键字
      • 3.2 package关键字
      • 3.3 import关键字
      • 3.4 super关键字
      • 3.6 static关键字
      • 3.6 final关键字
      • 3.7 instanceof关键字
      • 3.8 abstract关键字与抽象类
      • 3.9 interface关键字与接口
    • 4. 浅谈设计模式
      • 4.1 MVC设计模式
      • 4.2 单例模式
      • 4.3 模板模式

前言

本文为B站Java教学视频BV1Kb411W75N的相关笔记,主要用于个人记录与分享,如有错误欢迎留言指出。

本章笔记涵盖视频内容P174 ~ P365

1. 类(Class)

  • 定义:类是对一类事物的描述,是抽象的,概念上的定义
  • 注意事项:
    • 如果创建了一个(非static的)类的多个对象,则每个对象都独立的拥有一套类的属性
    • 不能使用形如Person1 = Person2来复制类,这样赋值仅仅交换了地址(和数组类似)
    • Java中的类和C中的结构体非常相似

类的组成部分

1.1 属性(成员变量)
  • 声明: 权限修饰符 数据类型 变量名

    class Test{
        String name;
    }
    
  • 对属性可以赋值的位置:

    ①默认初始化

    ②显式初始化 / ③在代码块中赋值

    ④构造器中初始化

    ⑤有了对象后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值

//Test.java
public class Test {
    public static void main(String[] args) {
        String name;	//默认初始化
        String name_a = "HI";	//显示初始化

        String name_b;
        {
            name_b = "HII";	//在代码块中赋值
        }

        Tests tests = new Tests();
        tests.name_d = "HIIII";	//有了对象后,通过"对象.属性"或"对象.方法"的方式进行赋值
    }
}

//Tests.java
public class Tests {

    String name_c;	
    String name_d;

    public Tests() {
        name_c = "HIII";	//构造器中初始化
    }
}
  • 属性(成员变量) 与 局部变量的区别:

    • 相同点:

      • 定义变量的格式:数据类型 变量名 = 变量值
      • 先声明,后使用
      • 变量都有其对应的作用域
    • 不同点:

      • 在类中声明的位置不同

        属性:直接定义在类内

        局部变量:声明在方法,方法形参,代码块,构造器形参,构造器内部

      • 关于权限修饰符的不同

        属性:可以在声明属性时,指明其权限,使用权限修饰符,如:private,public,protected,缺省

        局部变量:不可以使用权限修饰符

      • 默认初始化值的情况:

        属性:类的属性,根据其类型,都有默认初始化值

        ​ 整型(byte,short,int,long):0

        ​ 浮点型(float,double):0.0

        ​ 字符型(char):0

        ​ 布尔型(boolean):false

        ​ 引用数据类型(类,数组,接口):null

        局部变量:没有默认初始化值,在调用之前必须要显式赋值。

        ​ 特别的,形参在调用时才需要赋值

      • 在内存中加载的位置:

        属性:加载到堆空间中(非static)

        局部变量:加载到栈空间

1.2 构造器
  • 声明: 权限修饰符 当前类名 (形参列表) {}

    //构造器可以创建并初始化对象的信息
    class Test{
        
        String name;
        
        //空参构造器
        public Test (){}
        
        public Test (String name){
            this.name = name;
        }
    }
    
  • 注意事项:

    1. 若没有显式定义类的构造器,则系统默认提供一个空参构造器
    2. 一个类中定义的多个构造器,彼此构成重载
    3. 一旦显示定义了类的构造器,系统便不再提供默认的空参构造器
    4. 一个类中,至少会有一个构造器
1.3 代码块
  • 声明:static(可选) {代码块}

    //代码块可用来初始化类或对象,只能使用static或"同步"修饰
    class Test{
        
        String name;
        
        public Test (){}
        
        public Test (String name){
            this.name = name;
        }
        
        {
            //代码块
        }
    }
    
  • 非静态代码块和静态代码块的比较

    非静态代码块 静态代码块
    内部可以有输出语句 内部可以有输出语句
    随着对象的创建而执行 随着类的加载而执行,而且只执行一次
    作用:可以在创建对象时,对对象的属性等进行初始化 作用:初始化类的信息
    如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
    每创建一个对象,就执行一次非静态代码块 静态代码块的执行要优先于非静态代码块的执行
    非静态代码块内可以调用静态或非静态的属性,方法 静态代码块内只能调用静态的属性,静态的方法,不能调用非静态的结构
  • 代码块更多的是和其它代码一起结合使用,用于界定不同代码之间的域。但是结合static或同步机制,代码块也可以"独立"发挥作用。

1.4 方法
  • 声明:权限修饰符 返回值类型 方法名 (形参列表) {方法体}

    //使用方法可以调用当前类的属性和方法
    class Tests{
    
        private String name;
    
        public Tests (){
    
        }
    
        public Tests (String name){
            this.name = name;
        }
    
        {
            //代码块
        }
    
        public void setName(String name){
            this.name = name;
        }
    }
    
  • 注意事项:

    1. 当方法A中又调用了方法A,称为递归

    2. 方法中不可以定义方法

    3. 方法形参在传参的时候,基本数据类型和String自身是不会因为方法内部值的改变而改变的。但是除了String的引用数据类型,由于传入的是地址值,所以方法内如果值发生改变,那么其本身值也会发生改变。

      (Java的方法和C的函数类似)

  • 方法的重载:

    在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可,与方法的权限修饰符,返回值类型,形参变量名,方法体均没有关系

    void show(int a,char b,double c){}
    int show(int z,char x,double y){}	//非重载
    void show(int a,double c,char b){}	//重载
    int show(int a,double c,char b){}	//重载
    
  • 方法的重写:

    • 子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作;重写以后,进行任何此方法的调用时(包括在父类内进行调用),实际执行的是子类中重写后的方法
    • 重写规定:
    1. 格式:权限修饰符 返回值类型 方法名 (形参列表) {方法体}
    2. 子类重写的方法的方法名和形参列表,必须与父类中被重写的方法的方法名和形参列表相同
    3. 子类重写的方法的权限修饰符,不能小于父类中被重写的方法的权限修饰符
      • 子类不能重写父类中声明为private权限的方法(如果执意在子类"重写",会出现"各用各的"情况)
    4. 返回值类型:
      • 父类被重写的方法的返回值是void,则子类重写的方法的返回值类型只能是void
      • 父类被重写的方法的返回值是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类(如父类方法返回值为Object,那么子类返回值就可以是String)
      • 父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型
    5. 子类重写的方法抛出的异常类型不能大于父类被重写的方法抛出的异常类型
    6. 子类和父类中的同名同参数的方法要么都声明为非static的,要么都声明为static的;声明为static时不算重写
    • 注意事项:
      • 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中(多态性,编译看左边,运行看右边)
    • 对于实例变量(如属性)则不存在这样的现象,即使子类中定义了与父类完全相同的实例变量,这个实例变量依旧无法覆盖父类中定义的实例变量(非多态性,编译运行都看左边)
    public class ExtendsTest {
        public static void main(String[] args) {
    
            Son son = new Son();
            Father father = new Father();
    
            son.Talk();		//输出:我是子类10
            father.Talk();	//输出:我是父类10
    
        }
    }
    
    class Father{
    
        public int a = 10;
    
        public void Talk(){
            System.out.println("我是父类" + a);
        }
    }
    
    class Son extends Father{
    
        public void Talk(){
            System.out.println("我是子类" + a);
        }
    
    }
    
  • 可变个数形参

    //格式:数据类型...变量名
    public void show(String ... strs){
        System.out.println("HERE!");
    }
    
    //当调用可变个数形参的方法时,传入的参数个数可以是0个,1个或多个
    test.show("hello");
    test.show("hello","world");
    
    //可变个数形参的方法若与本类中方法名相同,形参不同的方法之间构成重载,且优先级比较低
    public void show(String strs){
        System.out.println("HERE!");
    }
    
    //可变个数形参在方法的形参中,必须声明在末尾;最多只能声明一个可变形参
    public void show(int n,String ... strs){
        System.out.println("HERE!");
    }
    
    //若要调用传入的参数,则参照数组使用下标的方式调用
    public void show(String ... strs){
        for(int i = 0;i < strs.length;i++){
            System.out.println(strs[i]);
        }
    }
    
    /*
    实际上多个形参的方法本质上使用的是数组的方式传参,相当于是public void show(String[] strs),只不过省去了创建数组挨个赋值的麻烦。注意public void show(String[] strs)是无法与public void show(String...strs)重载的,两者会互相冲突
    */
    
  • 关于"多态性编译看左边,运行看右边"的理解

    //对于展现多态性的代码(如下),在编译的时候只会看父类(左边)的代码,在运行的时候才会看右边(子类)的代码
    Animal p = new Cat();	//这里Cat是Animal的子类
    
    //而对于非多态性的代码,在编译和运行的时候都只会看左边的代码
    Aniaml p = new Animal();
    
1.5 内部类
  • 定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类

  • 成员内部类(静态,非静态)

    • 作为内部类的成员(不同之处):
      • 调用外部类的结构
      • 可以被static修饰
      • 可以被4种不同的权限修饰
    • 作为一个类(相同之处):
      • 类内可以定义属性,方法,构造器等
      • 可以被final修饰,表示此类不能被继承
      • 可以被abstract修饰
    //实例化成员内部类的对象
    public class Test {
        public static void main(String[] args) {
            //创建Dog实例(静态的成员内部类),由于是静态内部类所以可以直接实例化
            Person.Dog dog = new Person.Dog();
            dog.show();
    
            //创建Bird实例(非静态的成员内部类),由于是非静态内部类所以必须要先实例化外部类才能实例化
            Person person = new Person();
            Person.bird bird = person.new bird();   //主要此处实例化对象和一般的不一样
        }
    }
    
    class Person {
        static class Dog{
            public void show(){
                System.out.println("I'm a dog!");
            }
        }
    
        class bird{
            public void show(){
                System.out.println("I'm a bird!");
            }
        }
    }
    
  • 局部内部类(方法内,代码块内,构造器内):

    class MyComparable implements Comparable{
        
        public int compareTo(Object o){
            return 0;
        }
    }
    return new MyComparable;
    //和匿名实现类类似
    
1.6 其它事项
  • Object类

    所有的java类都直接或间接的继承于java.lang.Object类。这意味着所有的java类具有java.lang.Object类声明的功能。

  • "=="和equals()

    • "=="的使用
    1. 可以使用在基本数据类型变量和引用数据类型变量中

    2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等(不要求类型相同)

      如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体

    • equals()的使用

      1. 只适用于引用数据类型
      2. Object类中定义的equals()和==的作用是相同的
      3. 像String,Date,File,包装类等都重写了Object类中的equals()方法。重写之后,比较的是两个对象的"实体内容"是否相同
      4. 通常,自定义的类如果使用equals(),就需要对Object类中的equals()进行重写,才能比较"实体内容"是否相同
  • 包装类(Wrapper)

    • 针对八种基本数据类型定义相应的引用类型,有了类的特点就可以调用类的方法

      基本数据类型 包装类
      byte Byte
      short Short
      int Interger
      long Long
      float Float
      double Double
      boolean Boolean
      char Character
    • 基本数据类型,String类型和包装类之间的转化

      1. 基本数据类型 → 包装类:调用包装类的构造器

        • Integer in1 = new Integer(num1);

          Interger in2 = new Interger("123");

        • 不符合格式的输入会报错;特别的,对于Boolean类型,接收字符串转化的时候,只要不是"true",都会默认为false

        • 这些包装类的初始化默认值也发生了改变,由于是类,初始值统一为null

      2. 包装类 → 基本数据类型:调用包装类的xxxValue()

        • int i1 = in1.intValue();

          float f2 = f1.floatValue();

        • 自动拆箱/自动装箱:

          int num2 = 10;
          boolean b1 = true;
           
          //"手动"装箱:
          Integer in1 = new Integer(num1);
          Boolean b2 = new Boolean(b1);
          //自动装箱:基本数据类型 → 包装类
          Integer in1 = num1;
          Boolean b2 = b1;
          //"手动"拆箱
          int num3 = in1.intValue();
          //自动拆箱:包装类 → 基本数据类型
          int num3 = in1;
          
      3. 基本数据类型,包装类 → String类型

        • 连接运算

          String str1 = num1 + "";

        • 调用String的valueOf(Xxx xxx)

          float f1 = 12.3f;

          String str2 = String.valueOf(f1);

      4. String类型 → 基本数据类型,包装类:调用包装类的parseXxx(String s)

        • int num2 = Interger.parseInt("123");

        • 不符合格式的输入会报错;特别的,对于Boolean类型,接收字符串转化的时候,只要不是"true",都会默认为false

2. 对象

  • 定义:对象是实际存在的该类事物的每个个体,也称为实例

2.1 封装性

  • 定义:在实际问题中,往往需要给属性赋值加入额外的限制条件。这个条件无法在属性声明时体现,所以只能通过方法进行限制条件的添加。因此,为了避免用户使用"对象.属性"的方式直接对属性进行赋值,需要将属性声明为私有的(private)。此时,针对于属性就体现了封装性。

  • 一般将类的属性Xxx私有化(private),同时提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值

修饰符 类内部 同一个包 不同包的子类 同一个工程
private Yes
缺省(default) Yes Yes
protected Yes Yes Yes
public Yes Yes Yes Yes

Java规定的四种权限:private < 缺省 < protected < public

四种权限都可以用来修饰类的内部结构:属性,方法,构造器,内部类;若要修饰类,只能使用缺省和public

(跨包使用的话要导包import)

2.2 继承性

  • 格式:class A extends B{}

    ​ A:子类,派生类,subclass

    ​ B:父类,超类,基类,superclass

  • 一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有属性和方法。特别的,父类中声明为private的属性或方法,子类继承父类之后,仍然获取了父类中私有的结构。只是因为封装性的影响,子类不能直接在类内调用父类的结构。

  • 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。

  • Java中关于继承性的规定:

    1. 一个类可以被多个子类继承
    2. Java中类的单继承性,一个类只能有一个父类
    3. 子父类是相对的概念

2.3 多态性

  • 多态性是一个比较抽象的性质,可以理解为父类的引用指向子类的对象

  • 有了对象的多态性后,在编译期只能调用父类中声明的方法,但是在运行期,实际执行的是子类重写父类后的方法。(编译看左边,运行看右边)

  • 多态性的使用前提:①类的继承关系 ②方法的重写 (对象的多态性只适用于方法,不适用于属性)

  • 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时只能调用父类中声明的属性和方法。

  • 使用强制类型转换符(向下转型)就可以使具有多态性的对象调用子类中特有的属性和方法

    //举例,若Man为Person的子类,则下方程序创建了一个具有多态性的对象,此对象无法调用Man中特有的方法
    Person p1 = new Man();
    
    //下方程序使用强制类型转换符,此时m1可以使用Man中特有的方法
    Man m1 = (Man)p1;
    m1.earnMoney();
    
    //使用强转时,可能会出现ClassCastException的异常
    Woman w1 = (Woman)p1;
    w1.goShopping();
    //创建多态对象的时候,p1使用的是Man类,所以即便强转也不能强转为与Man同级的Woman
    

2.4 其它事项

  • 匿名对象:创建的对象,没有显式的赋给一个变量名,即为匿名对象

    ​ 特征:匿名对象只能调用一次

    ​ 使用:如,mall.show(new Phone()); 直接创建一个对象给方法使用

3. 关键字

3.1 this关键字

  • 定义:this可以理解为当前对象,或当前正在创建的对象;this可用来修饰属性,方法,构造器

  • 应用场景:

    1. this指定变量

      在类的方法或构造器中,可以使用"this.属性"或"this.方法"的方式,调用当前对象的属性或方法,但是一般情况下都会省略"this."。特别的,当方法的形参和类的属性同名时,必须显式的使用“this.变量”的方式,表明此变量是属性而非形参。

      class Person{
          
          String name;
          int age;
          
          //被隐藏的this (this.name = n;)
      	public void setName(String n){
          	name = n;
      	}
          
          //必须要添加的this
          public void setAge(int age){
              this.age = age;
          }
      }
      
    2. this调用构造器

      • 在类的构造器中,可以显式的使用"this(形参列表)"的方式,调用本类中指定的其它构造器
      • 构造器中不能通过"this (形参列表)"的方式调用自己
      public Person(int age){
          this.age = age;
      }
      
      public Person(String name,int age){
          this(age);	
          //相当于当前的Person调用的上方Person构造器,复用了上方构造器的代码,简化了代码量
          this.name = name;
      }
      
    3. 在类内快速调用自身

      public class Girl{
          
          String name;
          int age;
          
          public Girl(String name, int age){
              this.name = name;
              this.age = age;
          }
          
          public String getName(){
              return name;
          }
          
          public void setName(String name){
              this.name = name; //以上this的使用都是1.的场景
          }
          
      //******************************************
          public int compare(Girl girl){
              return this.age - girl.age;
          }
      //******************************************
      /*
      此处的this指的是调用者,比如A.compare(B),那么A就是类内的this,而B就是形参。这样做的好处就是省去了在形参内再写一次A的麻烦,让程序更加直观且简洁
      */
      }
      

3.2 package关键字

  • 包的概念可以更好的实现项目的管理

  • 使用package声明类或接口所属的包,声明在源文件的首行

  • 每"."一次,就代表一层文件目录

  • 同一个包下,不能命名同名的接口,类

    不同的包下,可以命名同名的接口,类

3.3 import关键字

  • 在源文件中使用import显式导入指定包下的类或接口,声明在包的声明和类的声明之间。

  • 如果需要导入多个类或接口,那么可以并列显式导入多个import,或者使用譬如"java.util.*"的写法一次性导入util包下所有的类和接口。

  • 如果导入的类或接口是java.lang包下的(如System),或者是当前包下的,则可以省略此import语句

  • 如果在代码中使用不同包下同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类。

3.4 super关键字

  • 定义:super可以用来调用父类中的属性,方法,构造器

  • 应用场景:

    • super调用属性和方法:

      1. 在子类的方法中,可以通过使用"super.属性"或"super.方法",显式的调用父类中声明的属性或方法。但是这种情况下,通常习惯省略"super."
      2. 特别的,当子类和父类中定义了同名的属性时,要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
      3. 特别的,当子类重写了父类中的方法以后,想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
    • super调用构造器:

      1. 可以在子类的构造器中显式的使用"super (形参列表)"的方式,调用父类中指定的构造器

      2. "super (形参列表)"的使用,必须声明在子类构造器的首行

      3. 在类的构造器中,对于"this (形参列表)"和"super (形参列表)"只能二选一,不能同时出现

      4. 在构造器的首行,若没有显式的声明"this (形参列表)"或"super (形参列表)",则默认调用的是父类中空参的构造器

      5. 在类的多个构造器中,至少有一个类的构造器使用了"super (形参列表)",调用父类中的构造器

    public class CheckAccount extends Account{
        
        private double overdraft;
        
        public CheckAccount(int id,double balance,double AIR,double overdraft){
            super(id,balance,AIR);
            this.overdraft = overdraft;
        }
        //此处直接调用父类的构造器进行初始化,而父类中没有的overdraft就要自己初始化
    }
    
  • super在使用上和this关键字有点像

3.6 static关键字

  • 定义:static可以用来修饰属性,方法,代码块,内部类

  • 使用static修饰的属性,称为静态变量(类变量)

    • 静态变量:当创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其它对象调用时,调用到修改后的变量
    • 实例变量:当创建了类的多个对象,每个对象都独立拥有一套类中的非静态属性。当修改其中一个对象的非静态属性时,不会导致其它对象中同样的属性值的修改。
  • 使用static修饰的方法,称为静态方法

    • 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用

    • 静态方法中,只能调用静态的方法或属性

      非静态方法中,既可以调用非静态的方法和属性,也可以调用静态的方法和属性

  • 应用场景:

    • static属性:被多个对象所共享的,不会随着对象的不同而不同的;类中的常量也常常声明为static
    • static方法:操作静态属性的方法;工具类中的方法也习惯性声明为static
  • 注意事项:

    1. 静态变量随着类的加载而加载,可以通过"类.静态变量"的方式进行调用
    2. 静态变量的加载要早于对象的创建
    3. 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在于方法区的静态域中
    4. 在静态的方法内,不能使用this和super关键字
public class Account{
    
    private int id;
    private String pwd = "000000";
    
    private static double interestRate;		
    private static double minMiney = 1.0;
    private static int init = 1001;
    //对于常量,以及需要长久记录并公用的变量,可以声明为static类
    
    public Account(){
        id = init++;	//由于init不会被重置,所以每一次创建Account,id都会是上一个的id+1
    }
    
    public static double getInterestRate(){
        return interestRate;
    }
    //static的变量,返回的方法也必须要是static的,反之同理
}

3.6 final关键字

  • 定义:final可以用来修饰类,方法,变量 (有些类似于C的const)

  • final 用来修饰类:表明此类不能被其他类所继承。

    ​ 如:String类,System类等

  • final 用来修饰方法:表明此方法不能被重写

    ​ 如:Object类中的getClass()

  • final用来修饰变量:此时的"变量"就称为是一个常量

    • final修饰属性:可以考虑赋值的位置有:显式初始化,代码块初始化,构造器初始化

    • final修饰局部变量:使用final修饰形参时,表明此形参是一个常量。当调用此方法时,给常量形参一个实参,一旦赋值以后,就只能在方法体内使用此形参,不能重新赋值

  • static final可以用来修饰属性或方法,修饰属性时属性称为全局常量

3.7 instanceof关键字

  • a instanceof A:判断对象a是否是类A的实例。如果是,返回true,否则返回false;
  • 若类B是类A的父类,则a instanceof B也返回true
  • 规律:小的能进大类,大的不能进小类

3.8 abstract关键字与抽象类

  • 定义:abstract可以用来修饰的结构,类,方法

  • abstract修饰类:抽象类

    • 此类不能实例化
    • 抽象类中一定会有构造器,便于子类实例化时调用
  • abstract修饰方法:抽象方法

    • 抽象方法只有方法的声明,没有方法体

    • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法。

    • 若子类重写了父类中所有的抽象方法,此子类可以实例化

      若子类没有重写父类中所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

      //抽象类(无法被创建对象)
      abstract class Employee{
    
          String name;
          int id;
          int salary;
      
          public Employee() {
          }
      
          public Employee(String name, int id, int salary) {
              this.name = name;
              this.id = id;
              this.salary = salary;
          }
      
          abstract public void work();	//抽象方法(没有方法体)
      }
    
  • 注意事项:

    1. abstract不能用来修饰属性,构造器等结构
    2. abstract不能用来修饰私有方法,静态方法,final的方法,final的类
  • 抽象类的匿名子类

    //非匿名类,非匿名对象
    Worker worker = new Worker();
    method1(worker);
    
    //非匿名类,匿名对象
    method1(new Worker());
    
    //匿名类,非匿名对象
    Person p = new Person(){
        public void eat{
            System.out.println("吃东西");
        }
    };
    method1(p);
    
    //匿名类,匿名对象
    method1(new Person(){
        public void eat{
            System.out.println("吃东西");
        }
    });
    

3.9 interface关键字与接口

  • 定义:interface用于定义接口。Java类可以实现多个接口,弥补了Java单继承性的局限性。
  • 格式:class AA extends BB impements CC,DD,EE
  • 接口中的成员:(在接口内书写时,可以省略前缀)
    • 全局常量:public static final Xxx
    • 抽象方法:public abstract Xxx
    • 静态方法:public static Xxx
    • 默认方法:public default Xxx
interface Flyable{
    //全局常量
    public static final int MAX_SPEED = 7900;
    int MIN_SPEED = 1; //省略前缀
    
    //抽象方法
    public abstract void fly();
    void stop();
}

interface Attackable{
    //...
}

class Bullet implements Flyable,Attackable{
    //重写方法
}
  • 注意事项:

    • 接口中不能定义构造器,这意味着接口不可实例化

    • Java开发中,接口通过让类去实现(implements)的方式来使用

      如果实现类实现了接口中的所有抽象方法,则此实现类就可以实例化

      如果实现类没有实现接口中所有抽象方法,则此实现类仍为一个接口

    • 接口与接口之间可以继承,而且可以多继承

    • 接口中定义的静态方法,只能通过接口来调用

    • 通过实现类的对象,可以调用接口中的默认方法;如果实现类重写了接口中的默认方法,调用时,调用的是重写以后的方法

    • 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的方法

    • 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下会报错

    • 在子类(或实现类)的方法中调用父类,接口中被重写的方法

      public void myMethod(){
          method3();//调用自己定义的重写的方法
          super.method3();//调用的是父类中声明的方法
          CompareA.super.method3();//调用接口中的默认方法
      }
      
  • 接口的匿名实现类:

    //USB是接口,Flash是USB接口的实现类
    Computer com = new Computer();
    
    //1.接口的非匿名实现类的非匿名对象
    Flash flash = new Flash();
    com.transferData(flash);
    
    //2.接口的非匿名实现类的匿名对象
    com.transferData(new Flash());
    
    //3.接口的匿名实现类的非匿名对象
    USB phone = new USB(){
        public void start(){
            //重写USB接口中的方法
        }
        
        public void stop(){
            //...
        }
    };
    com.transferData(phone);
    
    //4.接口的匿名实现类的匿名对象
    com.transferData(new USB(){
        public void start(){
            //...	
        }
        
        public void stop(){
            //...
        }
    });
    

4. 浅谈设计模式

4.1 MVC设计模式

模型层 model(主要处理数据)
数据对象封装 model.bean/domain
数据库操作类 model.dao
数据库 model.db
控制层 controller(处理业务逻辑)
应用界面相关 controller.activity
存放fragment controller.fragment
显示列表的适配器 controller.adapter
服务相关 controller.service
抽取的基类 controller.base
视图层 view(显示数据)
相关工具类 view.utils
自定义view view.ui

4.2 单例模式

  • 定义:单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例

    • 饿汉式:声明类对象后立刻初始化,实例在程序运行中长久存在

      class Bank{
              
              //私有化类的构造器
              private Bank(){}
              
              //内部创建类的对象,要求此对象也是静态的
              private static Bank instance = new Bank();
              
              //提供公共的静态的方法,返回类的对象
              public static Bank getInstance(){
          		return instance;
              }
      }
      
    • 懒汉式(不完善):声明类对象后先不初始化,等要使用的时候再初始化

      class Bank{
              
              //私有化类的构造器
              private Bank(){}
              
              //声明当前类对象,没有初始化,要求此对象是静态的
              private static Bank instance = null;
              
              //提供公共的静态的方法,创建实例并返回类的对象
              public static Bank getInstance(){
                  if(instance == null){
                      instance = new Order();
                  }
                  
                  return instance;
              }
      }
      
    • 饿汉式和懒汉式的优缺点对比:

      饿汉式 懒汉式
      优点 是线程安全的 延迟对象的创建
      缺点 对象加载(存在)时间过长 "目前"线程不安全

4.3 模板模式

  • 定义:在开发中实现一个算法时,整体步骤很固定,通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现,这就是模板模式。

    //计算某段代码执行所需要的时间
    abstract class Template{
        public void spendTime(){
            
            long start = System.currentTimeMillis();
            
            code();//不确定的部分,易变的部分
            
            long end = System.currentTimeMillis();
            
            System.out.println("花费的时间为:" + (end - start));
        }
        
        public abstract void code;
    }
    
这篇关于尚硅谷Java入门笔记 - P174 ~ P363的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!