王道Java40th笔记(0403)

基础知识


全限定类名

包含包名的方法名全称;防止因为类名重复,编译器就近原则选择错方法

转义字符

/b 退格

/t Tab

nextLine

nextLine() 后面不要使用 next*() 会导致读取错误

foreach

for(ElemType et:容器名)

Java仅有值传递

  1. 值传递:方法接收的不是实参本身,而是实参一个拷贝;因此方法是不能对实参做出修改
  2. 引用传递:方法接收就是实参本身(实参的地址),不是拷贝对象,方法是可以对实参做出修改

注解

@Override: 限定某个方法,是重写父类方法, 编译检查
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@FunctionalInterface:功能接口
@SuppressWarnings: 抑制编译器警告

Random 特性

左闭右开[ )

优先级提升

// 三元运算符为一个整体,混合运算优先级以最高的为准
Object obj = true?new Integer(1):new Double(2);
System.out.println(obj); // 1.0 Integer --> Double

final byte a = 1;
final byte b = 2;
byte c = a + b; // 编译通过,a,b为常量,类型不提升
byte d = a + c; // 编译不通过,c为变量,右侧运算类型为int


类的成员

属性(成员变量),方法,构造器,代码块,内部类

默认的初始化

  • 基本数据类型作为 类成员 的时候,即使没有进行初始化。Java也会给定默认的初始值
  • 局部变量没有默认值,需要依靠手动初始化

内存分布

  • 基本数据类型,局部变量 --- 栈帧

  • 引用数据类型---栈帧(引用)+堆(对象)

  • 栈 --- 局部变量 --- 没有默认值,需要初始化才可用

  • 堆 --- 存储对象 --- 在初始化前就有了默认值(即使指定赋值非空,也先赋默认值null,再赋指定值)

类加载

  • 过程:加载 --> 连接(默认赋值) --> 初始化
  • 在创建对象 new 前,会类加载(类加载的一部分【加载,连接】)
  • 访问类的静态成员 类名.静态成员 前,会类加载
  • 启动 main 方法前也会对main所在的类进行类加载
  • 子类 的类加载会触发 父类 的类加载;先父后子
    • 子类名.父类静态成员 不进行子类的类加载
    • 创建子类对象时,不会连带创建父类对象,父类的成员会创建在子类对象(堆)的专门区域里, super 指向这块区域
  • 类加载 仅加载一次 ,无论之后是否创建对象,调用方法,都不会再进行类加载
  • 类加载,执行带有 static 的语句和代码块,连接时对静态成员初始化,与显示初始化语句无关
  • 基本数据类型 和 String 的 全局常量static final 调用不触发类加载(不在类的静态常量池中)

构造器(是类就有)

  • 用来赋值初始化,而不是创建对象
  • 赋值顺序:默认值赋值--> 显示初始值赋值 --> 构造器形参赋值
  • this(参数1,参数2,...) 显示调用对应参数的构造器,仅能够在构造器内的 第一行调用一次super 同样

this

Student s = new Student();

对象名.成员方法 隐含形参 this ,默认传递引用 s

静态成员方法不含 this 如果调用成员方法,需要手动对象实例化

Super

不是引用,但可以当父类引用使用,指向子类对象的一片特殊区域

成员变量的赋值

  1. 静态成员变量在类加载时初始化(默认赋值 --> 显示赋值)
  2. 成员变量在创建对象时由构造代码块和构造器赋值
  3. 类加载先于对象的创建,因此静态成员初始化早于成员变量
  4. 赋值顺序一般是:默认值赋值-->显示赋值/构造代码块赋值-->构造器赋值
  5. 构造代码块赋值 与 显示赋值 顺序执行

代码块

  • 构造代码块:在构造器调用时执行;在显示赋值,构造代码块同时存在时--顺序执行(块内不能使用this调用构造器)
    • 仅可以给成员变量赋值,块内定义的变量是局部变量,不是成员
    • 类加载不执行,new执行
    • 应用:提取出构造器的公共语句,写入构造代码块 -- 编译自动添加到每个构造器中
  • 静态代码块:在类加载时执行
    • 应用:用于给类的静态成员赋值,调用一次的方法,测试类加载

访问权限修饰符

用来限定类和类的成员

  1. private :只能够在同一类中能够访问,私有的,外面谁都不能用。
  2. 默认(缺省):同一包中的子类或者其它类能够访问,同包中都可以使用。
  3. protected :不同包的子类能够通过创建 子类对象 访问父类,同包可任意访问。
    • 不同包的子类,只有创建 子类自身对象 ,才可以访问父类成员
    • 目的:防止滥用,仅仅提供给子类使用
  4. public :没有限制

继承的特性

  1. 关系:子类 is-a 父类

  2. 子类名.父类静态方法 访问父类静态方法

  3. 子类的类加载会触发父类的类加载,并且类加载的顺序是 先父后子

  4. 类对象创建的过程中,父类的构造方法会被调用,但是不会创建父类的对象

    子类构造器隐含 super();

  5. 子类对象中会专门开辟一片独立的区域,用来存储父类的成员变量

  6. superthis 两个关键字在表示调用构造器时,不能共存

  7. 子类含有父类同名成员,父类同名成员会被隐藏,可用 super 调用

  8. 静态成员变量,没有继承关系;父子类同名静态成员有各自的存储空间,互不干涉

  9. 默认直接继承Object ,一旦手动继承了其他类,则变成了间接继承了Object 即继承类直接继承Object (如果继承类没有显示继承其他类的时)

  10. 子类 与 父类 有同名成员变量 父类变量被隐藏,有同名成员方法 父类方法被覆盖;但都可以使用super来调用

    • 对象名.成员变量 的范围和值,都由引用的数据类型来决定,因为编译器只能看引用,对象要在创建时进行类加载才可显示
    • 对象名.方法名 的范围和调用结果,是根据 new 对象的实际类型 来决定的(多态)[编译看左,运行看右]

子类重写的限制

  1. 保持一致 : 方法名,形参列表
  2. 保持兼容:访问权限等级,返回值类型(引用类型)

重写 & 重载

方法重载Overload 方法重写Override
同类中 父子类
方法名 相同 相同
参数列表 不同 相同
访问权限 不影响 子类方法的访问权限 >= 父类访问权限
返回类型 不影响 引用类型保持兼容

构造方法,静态方法,私有方法,final方法 -- 不能重写

多态

  • 条件:存在继承,方法重写,父类引用指向不同子类对象
  • 特征:父类引用,指向不同子类,不同子类重写了同名方法,调用这个会产生不同效果
  • 区分:父子类存在同名成员变量,表现出属性的隐藏
  • 父类引用不能直接调用 子类特有 的方法,需要强转为子类引用再调用
  • 强制向下转型的条件:父类(PA)的引用指向子类对象(A),那么只能转为子类(A)引用,而不能强转为兄弟姐妹的引用(B,C ...)
    • 需要使用 if(引用名 instanceof 类名/接口名) 判断,保障向下转型安全性

final

  • 修饰的类不能被继承

  • 修饰的方法不能被重写

  • 修饰的基本数据类型则值不能改变 -- 常量;

  • 修饰的变量是引用类型则不能再指向其他对象,但内容可以改变

  • 修饰的成员变量,则没有了默认赋值,需要手动赋值(显示赋值/构造代码块/构造器),如果使用构造器赋值,则要保证所有构造器都能给final成员变量赋值

    final char[] chars ={'a'};//final 限定的是引用(地址)
    char[] chars1 = {'b'};
    
    chars[0] = 'c'; // 修改的是值,可以
    chars = chars1; // 修改的是地址,不行
    

抽象类Abstract

  1. 定义:可以定义抽象方法的普通类,除了无法创建对象,其他都可
  2. 普通类,普通类继承抽象类,必须实现所有的抽象方法。
  3. 抽象类,抽象子类继承可以自由选择实现
  4. abstract修饰方法时,不能有private,static,final

接口 Interface (常用)

  1. 接口表示一种开发标准,一种规范。表示对功能的扩展,它没有直接继承 is-a 关系,不强调属性抽象,强调行为抽象。因此大多数接口没有全局常量的,只有方法
  2. 接口不是类,没有构造器,没有代码块,不能继承类,支持多接口继承
  3. 如果一个类实现接口并继承别的类,要先继承再实现
  4. 一个类可以在 继承别的类的同时 实现多个接口
  5. 接口有 abstract 属性,可定义抽象方法,不能使用 final ,不能创建对象
  6. 一个类要先继承类,再实现接口
  7. 接口中的成员变量默认都是 public static final 修饰的,只能显式赋值;方法默认 public abstract
  8. 允许接口存在实现方法 default 返回类型 方法名{} ,需要实现的就自己重写,不需要的就直接继承

内部类

成员内部类

  • 目的:将一个类(Inner)的访问权限限定为一个类(Outer),并且使得这个类(Inner)能够访问外部类(Outer)的全部成员

  • 类加载,先外后内

  • 有四种访问权限修饰符

  • Inner 与 Outer 之间成员访问不受限;Inner 访问外部同名变量 外部类名.this

  • static 声明,全局常量 final static 除外(不会触发类加载)

  • 可以通过多个内部类分别基础多个类,来间接实现多继承

  • 调用依赖外部类对象

    // 外部静态方法,创建内部类对象
    Inner in = new Outer().new Inner();
    
    // 在外部(OtherOuter)创建内部类对象
    Outer.Inner oi = new Outer().new Inner();
    

静态内部类

  • 目的:借助Outer来隐藏和保护自身

  • 只能继承 static

  • 与普通类功能相同,与外部类(Outer)是 平行关系,静态内部类的类加载不会触发Outer的类加载

    // 在外部(OtherOuter)创建静态内部类对象
    Outer.Inner oi = new OuterInner();
    

局部内部类

  • 目的:继承实现外部类和接口,助Outer来隐藏和保护自身

  • 定义在方法中/代码块中,作用域也是方法中/代码块中

    • 外部类和外部其他类(非包含该内部类的类)不能访问内部类成员
  • 功能属性与成员内部类相同,但无访问修饰符

  • 可直接访问外部类所有成员,重名遵循就近原则

    // 特殊的一些用法
    public class Demo {
        public static void main(String[] args) {
            IA ia = EncloseClazz.method();
            // 通过对象访问超出生命周期的局部变量,JVM会把它转为成员变量
            ia.test();
        }
    }
    
    class EncloseClazz {
        public static IA method() {
            // 默认常量,不可修改;由test()在外部调用,会被JVM添加为Inner的成员
            int a = 10; 
            class Inner implements IA {
                @Override
                public void test() {
                    System.out.println(a);
                }
            }
            return new Inner();
        }
    }
    

匿名内部类(取代局部内部类,常用)

  1. 目的:简化代码,一次性调用
  2. 定义在类的局部位置,作用域在定义的方法/代码块中;
  3. 功能与局部内部类相同
  4. 是类,也是一个 继承/接口子类 的对象,因此可以作为传入方法的实参
//如果继承的是一个类,()用来调用 父类构造器 赋值 
new 类名/接口名(){
   // 重写方法体	      
};

Lambda (常用)

  • 目的:取代实现功能接口的匿名内部类

    • 功能接口:有且仅有一个需要实现抽象方法A的接口(如由Object继承的,无需实现的抽象方法,不算),实现方法数量不限

      () -> {}; // () 为A的形参列表;{}为重写A的方法体
      a -> {};  // 单参数可省()
      () -> 【方法体为一句话】; //方法体仅含有一句话,可省略{}
      () -> 【return的内容】; // 方法体仅含有return语句,可直接写返回内容
      
  • Lambda表达式本质是实现了接口的子类对象

    • 如果单独使用,需要使用功能接口或其父接口的 引用接收
    • 也可以当做 对象 使用(形参,返回值,对象.方法)
  • 方法引用

    • 方法返回值 与 功能接口的返回类型 兼容

    • 方法形参列表 与 功能接口的抽象方法A类型 一致

      () -> 方法名(); // 方法用来代替{}重写的方法体
      归属者::方法名;	 
      
  • 一些特性

    • Lambda表达式 没有自己的作用域,与包含自己的作用域同域
  • 应用

    • 回调方法:将Lambda对象作为一条规则传进方法

      public class CallBack {
          public static void main(String[] args) {
              RealCompare realCompare = new RealCompare();
              // 将一个对象(Lambda)作为`参数`传递进一个方法
              realCompare.comDouble(9, 4, (a, b) -> a > b ? a : b); // 求最大值
          }
      }
      
      class RealCompare {
          // 接受Lambda对象的是功能接口的引用
          void comDouble(double a, double b, Compare compare) {
              System.out.println("result = " + compare.comDouble(a, b));
          }
      }
      
      interface Compare {
          double comDouble(double a, double b);
      }
      

设计模式


单例

  • 目的:使得一个类,只能创建一个对象

  • 实现:私有化构造方法 --> 在类内静态实例化 --> 提供获取静态实例的公有方法

// 饿汉式:加载就实例化,可能浪费资源
public class Day3MyDemo {

    private int id;
    private String name;
    // 创建私有化静态(保证唯一性)对象实例
    private static Day3MyDemo d3 = new Day3MyDemo(1, "张三");
    // 私有化构造方法,防止类外new新的对象
    private Day3MyDemo(int id, String name) {
        this.id = id;
        this.name = name;
    }
    // 外部获取对象的方式
    public static Day3MyDemo getInstance(){
        return d3;
    }
}
// 懒汉式:使用时才实例化,存在线程安全问题
public class Day3MyDemo {

    private int id;
    private String name;
    // 私有化构造方法,防止类外new新的对象
    private Day3MyDemo(int id, String name) {
        this.id = id;
        this.name = name;
    }
    // 只声明,不实例化
    private static Day3MyDemo day3MyDemo = null;
    // 需要用时才实例化,多线程存在线程安全问题
    public static Day3MyDemo getInstance(){
        if (day3MyDemo == null){
            day3MyDemo = new Day3MyDemo(1,"张三");
     	}
     	return day3MyDemo;
	}
}
posted @ 2022-03-30 09:02  Raink  阅读(170)  评论(0编辑  收藏  举报