java-day0910-静态抽象内部类

第七章 静态、抽象、内部类

static


  1. static 修饰属性,方法,代码块、内部类。

    静态【贵族】非静态【平民】
    属性属于谁属于类属于对象
    属性调用类名访问(推荐)、对象访问对象访问
    属性特有?共享?所有对象共享对象特有
    属性初始化时间类加载到内存时创建对象后
    方法调用只能调用静态方法静态方法 + 非静态方法
    • 静态属性是属于类的,可以直接使用类名来访问,也可以使用对象访问,但推荐使用类名访问

    • 非静态的成员变量是属于对象特有的,

      静态的成员变量是所有对象所共享

    • 静态属性是属于类的,只要类加载到内存了,就可以使用类名来访问。

      非静态属性是属于对象的,只有创建出对象了,使用对象才可以访问。

    • 非静态方法中可以调用静态方法,【贵族平民】

      静态方法中只能调用静态的。

    • 属性的初始化时间:【饮水机和同学们的水杯】

      • 非静态属性创建对象后,系统会自动给对象中的非静态属性做初始化赋默认值,也正是因为这个原因,非静态属性只有在创建对象后,使用对象才能访问。
      • 静态属性类加载到内存中(方法区)的时候,系统就会给类中的静态属性做初始化赋默认值,所以,即使还没有创建对象,只要这个类加载到了内存,就可以直接使用类名来访问静态属性,因为这个时候静态属性已经完成了初始化赋默认值的操作。
    • 在非静态方法中,是否可以直接访问类中的静态属性和静态方法?

      • 是可以的,因为非静态方法都可以调用了,说明肯定已经创建对象了,同时也说明了这个类早就完成了类加载,那么类中的静态属性和静态方法,现在肯定是可以访问和调用的。
  2. 静态属性的存储位置
    类中的静态属性,跟随着类,一起保存在内存中的方法区

  3. 类中的构造器,可以给非静态属性做初始化,但是不能给静态属性做初始化。

    • 因为我们可以绕过创建对象的步骤,直接使用类名访问这个静态属性。

    • 注意:一般不使用构造器初始化静态属性。

  4. 静态代码块,也叫做静态初始化代码块,它的作用就是给类中的静态属性做初始化的。

  5. 注意:不能使用this在静态方法中,this表示调用方法的对象。

  6. 静态代码块的执行时刻

    • 由于静态代码块没有名字,我们并不能主动调用,它会在类加载的时候,自动执行。
      所以静态代码块,可以更早的给类中的静态属性,进行初始化赋值操作。
    • 并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次!
  7. 匿名代码块
    一种非静态代码块,也叫做匿名代码块,它的作用是给非静态属性做初始化操作

    • 每次创建一个对象,会默认调用一次非静态代码块。
  8. 匿名代码块执行的时刻

    • 由于匿名代码块没有名字,我们并不能主动调用,它会在创建对象时,构造器执行之,自动执行。
    • 并且每次创建对象之前,匿名代码块都会被自动执行。
  9. 执行顺序

    • 在一个类中

      • 先静态,再非静态

      • 静态:静态属性默认赋值 > 静态属性显式赋值 >静态代码块

      • 非静态:匿名代码块 > 构造器

        ​ 父类构造器 > 子类属性的显式赋值 > 子类匿名代码块 > 子类构造器

        【一般属性定义在匿名代码块前面,所以在前】

        【如果匿名代码块定义在属性显式赋值前,执行顺序:匿名代码块 > 属性显式赋值。】

      • 混合:静态代码块 > 匿名代码块 > 构造器

    • 在子父类中

      • 父类 > 子类
  10. 类的加载 :子类和父类 中 静态的

    创建对象: 子类、父类 中 非静态的

  11. 只要加载子类,它就会执行父类中静态属性赋值和静态代码块

  12. 静态导入:在自己的类中,要使用另一个类中的静态属性和静态方法,那么可以进行静态导入,导入完成后,可以直接使用这个类中的静态属性和静态方法,而不用在前面加上类名

  13. 子父类中,静态方法不属于重写,是新的方法。

  14. 静态与非静态,与类、与对象的关系。

final


  1. final修饰符,可以用来修饰类、变量、方法。

    • final修饰的类,无法被继承。

    • 用final修饰的方法可以被继承,不能被重写。

    • 用final修饰的变量就变成了常量,并且它只能被赋一次值,第二次赋值就会报错

      (常量不能重新赋值。)

  2. final常量赋值:

    • 声明的同时赋值(显式赋值)
    • 匿名代码块中赋值
    • 构造器中赋值
      • 使用构造器给常量赋值时,所有构造器必须对此常量进行赋值。

abstract


  1. abstract修饰符,可以修饰类、方法

  2. 抽象类不能创建对象,抽象方法没有方法体。

  3. 抽象方法的特点

    • 只有方法的声明 //方法的声明:public void test()
    • 没有方法的实现 //方法的实现:{}
  4. 普通子类继承了抽象父类,需要实现父类中所有的抽象方法。

    • 子类是抽象类,需要实现父类及其间接抽象父类中的抽象方法。
  5. 抽象方法一定是在抽象类当中

    抽象类中可以不包含抽象方法。

  6. 抽象类和非抽象类的区别

    抽象类非抽象类
    修饰符abstract修饰符没有使用abstract
    抽象方法可以有不能有抽象方法
    创建对象不能创建对象可以创建对象
  7. 抽象类和抽象方法的关系

    • 抽象类中可以没有抽象方法
    • 有抽象方法的类,一定要声明为抽象类
  8. 既然抽象类不能被实例化创建对象,那么这个类有什么用?

    • 抽象类是用来被子类继承的,子类继承抽象类,并且实现抽象类中的抽象方法。

      (实现抽象方法当做重写方法)

  9. 抽象类不实例化创建对象,那么抽象类中是否有构造器

    • 构造器,这个构造器是让子类调用的,子类继承父类,子类创建对象的时候,会先调用父类的构造器!(对父类的属性进行初始化)

interface接口


  1. 接口:使用interface关键字
  2. 接口的内部主要就是封装了方法和静态常量。
  3. 接口最终也会被编译成.class文件。
  4. 接口中没有静态代码块,通过显式赋值操作静态常量。
  5. 接口使用 extends 继承其他接口。
  6. 注意
    • 接口中的属性都是公共的静态常量 (默认就是静态的 int b = 0;)
    • 接口中的方法一般都是抽象方法 (默认修饰符就是public abstract)
      • 注意:JDK8中,还允许在接口中编写静态方法和默认方法
      • 注意:JDK9中,还允许在接口中编写私有方法
    • 接口的中抽象方法,不需要使用 abstract 修饰符,因为接口中的方法默认就是抽象方法
    • 接口里面的属性,默认就是public static final修饰的
      接口里面的方法,默认就是public abstract修饰的
      所以这些都可以省去不写的
  7. 类和类之间的关系是继承,类和接口之间的关系是实现:一个类实现了一个或多个接口
  8. 单继承,多实现
  9. 一个类实现了接口,那么就要实现接口中所有的抽象方法。
  10. 接口类型的引用可以指向任意的实现类对象。(多态)
  11. java中,类和类之间是单继承,类和接口之间是多继承
  12. 接口的引用调用方法,调用到的是实现类中重写的方法
    • 接口类型的引用,不能直接调用实现类中特有的方法。

访问控制


  1. public > protected > default > private

    修饰符类中同包非子类同包子类不同包子类不同包非子类
    publicYYYYY
    protectedYYYYN
    defaultYYYNN
    privateYNNNN
    • public_公共的:在所有地方都可以访问
    • protected_受保护的:当前类中、子类中,同一个包中其他类中可以访问
    • default_默认的:当前类中、同一个包中的子类中可以访问
      • 注意,default默认的,指的是空修饰符,并不是default这个关键字
        例如,String name; 在类中,这种情况就是默认的修饰符
    • private_私有的:当前类中可以访问
  2. new对象,方法参数(Test2 t),public Test2 t (不去new只声明) 。

  3. 权限

    • public:所有权限
    • protected:包权限(同包) 或 子类
      • 同包下,使用引用调用
      • 不同包下,不能使用引用调用,只能通过继承调用。
    • defalut : 包权限 (同包)
    • private:当前类中
  4. 父类的引用不能调用父类受保护的方法和受保护的属性。?写代码检测-子类吧?

内部类


  1. 内部类,不是在一个java源文件中编写俩个平行的类,而是在一个类的内部再定义另外的一个类。

  2. 匿名内部类【很重要】

    • 创建抽象类Person子类 --> 匿名内部类
      • new Person() {} ;
    • 匿名内部类可以定义特有的方法,但无法去调用。
    • 不能在匿名内部类中定义构造器
    • 写在方法中时,只能在创建匿名内部类的方法中使用。
    • 实现的代码只调用一次时,通过匿名内部类实现。
    • 创建匿名内部类
      • 简化了创建子类对象,简化重写方法。
      • 缺点:范围只在当前方法中 (解决:通过定义成员变量)测试
    • 注意,如果用父类型声明这个匿名内部类,那么这个匿名内部类默认就是这个父类型的子类
    • 匿名内部类的俩种形式
      • 利用一个父类,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个父类的子类型
      • 利用一个接口,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个接口的实现类
    • 匿名内部类因为没有类名
      • 匿名内部类必须依托于一个父类型或者一个接口
      • 匿名内部类在声明的同时,就必须创建出对象,否则后面就没法创建了
      • 匿名内部类中无法定义构造器
  3. 成员内部类

    • 类中,可以定义成员方法、成员变量,除此之外,还可以定义成员内部类

    • 注意,成员内部类中,不能编写静态的属性和方法。
      注意,当前这个代码,编译成功后,会生成俩个class文件,一个外部类,一个内部类。

      • 外部类的方法,访问成员内部类的属性和方法,需要创建内部类对象,然后才可以访问。

      • 如果这个成员内部类不是private修饰的,那么在其他类中就可以访问到这个内部类

    • 在其他类中,使用这个非private修饰的成员内部类的时候,需要注意以下几点:
      \1. 这个内部类需要import导入,并且在其他包中是 外部类.内部类 的形式导入。
      \2. 在创建对象的时候,需要先创建出外部类对象,然后使用外部类对象再创建内部类对象。形式为:外部类对象.new 内部类对象();

    • 类的内部除了嵌套另一个类之外,是否还可以嵌套接口?

      • 以,不仅类中可以嵌套接口,接口的内部也可以嵌套其他接口。
  4. 静态内部类

    • 静态内部类和成员内部类是类似的,只是这个内部类,多了static关键字进行修饰。
    • 注意,静态内部类中,【可以】编写静态的属性和方法,另外在四种内部类中,只有静态内部类可以编写静态属性和方法
    • 注意,在静态内部类中访问不了外部类中的非静态属性和方法
    • 在其他类中,使用这个非private修饰的静态内部类的时候,需要注意以下几点:
      \1. 这个内部类需要import导入,并且是 外部类.内部类 的形式导入。
      \2. 在创建对象的时候,直接使用这个静态内部类的名字即可:new 静态内部类对象(); ,不再需要依赖外部类对象了。
  5. 局部内部类

    • 局部内部类,是另一种形式的内部,在声明在外部类的方法中,相当于方法中的局部变量的位置,它的作用范围只是在当前方法中
    • 局部内部类中,访问当前方法中的变量,这个变量必须是final修饰的
      • 注意:在JDK1.8中,一个局部变量在局部内部类中进行访问了,那么这个局部变量自动变为final修饰
  6. 内部类的选择
    假设现在已经确定了要使用内部类,那么一般情况下,该如何选择?
    \1. 考虑这个内部类,如果需要反复的进行多次使用(必须有名字

      • 在这个内部类中,如果需要定义静态的属性和方法,选择使用静态内部类
      • 在这个内部类中,如果需要访问外部类的非静态属性和方法,选择使用成员内部类

    \2. 考虑这个内部类,如果只需要使用一次(可以没有名字

      • 选择使用匿名内部类

    \3. 局部内部类,几乎不会使用

包装类


  1. 包装类,是用来解决无法使用面向对象处理基本数据类型问题。

  2. 创建Integer对象:new 或者 Integer.valueOf()获取对象

  3. parseInt():将字符串参数解析为带符号的十进制整数。

    valueOf():返回一个Integer对象。

    intValue():将Integer的值作为int

    • 装箱的时候自动调用的是Integer的valueOf(int)方法。
    • 而在拆箱的时候自动调用的是Integer的intValue方法。
  4. JDK1.5或以上,可以支持基本类型和包装类型之间的自动装箱、自动拆箱

  5. 自动装箱使用的是同一个对象,范围在-128~127。

  6. 当自动装箱 或者 调用Integer.valueOf(),当数值在-128~127之间,Integer通过获取内部类的缓存数组,返回已存在的对象。(是一个对象数组)

    • 超过范围,会新建对象。
  7. 同一对应类型才能自动装箱。

Object常用方法


  1. toString方法

    • 该方法可以返回一个对象默认的字符串形式

    • System.out.println(stu);

      System.out.println(stu.toString())

      注意,默认情况下,println方法会调用这个对象的toString方法
      注意,推荐使用第一种,因为当stu的值为null时,第二种输出方式会报错,空指针异常

  2. getClass方法

    • 它可以返回一个引用在运行时所指向的对象,具体类型是什么
    • 子类中不能重写getClass,调用的一定是Object中的getClass方法:
  3. equals方法

    • 该方法可以比较俩个对象是否相等
    • Object中的equals方法,是直接使用的==号进行的比较,比较俩个对象的地址值是否相等
    • 对equals方法重写,一般需要注意以下几点
      \1. 自反性:对任意引用obj,obj.equals(obj)的返回值一定为true.
      \2. 对称性:对于任何引用o1、o2,当且仅当o1.equals(o2)返回值为true时,o2.equals(o1)的返回值一定为true;
      \3. 传递性:如果o1.equals(o2)为true, o2.equals(o3)为true,则o1.equals(o3)也一定为true
      \4. 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
      \5. 非空性:任何非空的引用obj,obj.equals(null)的返回值一定为false
  4. hashCode方法

    • 该方法返回一个int值,该int值是JVM根据对象在内存的中的特征(地址值),通过hash算法计算出的一个结果。
      • Hash,一般翻译做“散列”,也可以音译为“哈希”,就是把任意长度的数据输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。
    • Object中的hashCode方法默认返回的是对象的内存地址
    • 对于俩个对象的hashCode值
      • 相等的俩个对象,hashCode值一定相等
      • hashCode值相同,俩个对象有可能相等,也可能不相等(压缩映射)
      • hashCode值不同,俩个对象一定不同 (-128~127 和 new 的)

关于String对象


  1. 字符串String,是程序中使用最多的一种数据,JVM在内存中专门设置了一块区域(字符串常量
    ),来提高字字符串对象的使用效率。
  2. JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
    • 为字符串开辟一个字符串常量池,类似于缓存区
    • 创建字符串常量时,首先会检查字符串常量池中是否存在该字符串,如果存在该字符串,则返回该实例的引用,如果不存在,则实例化创建该字符串,并放入池中
  3. String str1 = “hello”;
    String str2 = new String(“hello”);
    • str1指向的是常量池中的hello对象
    • str2指向的是堆区中新创建的hello对象
  4. 只有用双引号,里面加入文字的方式,才会利用到内存中的字符串常量池
  5. 注意,使用+拼接的字符串也会利用字符串常量池,但是参与+号拼接的必须是双引号的形式才可以
  6. 当调用 intern() 方法时,JVM会将字符串添加到常量池中,并返回指向该常量的引用

查漏补缺

  1. == 和 equals() 各自的概念 ,区别,场景。

    • == 是直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的。

      • 对于基本数据类型,在常量池中,一个常量只会对应一个地址(范围:-128~127)
    • equals(),比较的是对象的内容。

      • Object类型的equals方法是直接==通过来比较的

        但是,所有的类都直接或间接地继承自java.lang.Object类。都可以重写equals方法。

      • 而基本类型的包装类,都重写了equals()方法,所以,比较的是对象的内容

  2. 注意:有变量参与拼接字符串,那么就不会使用常量池了

  3. String s = new String(); //表示空字符串 “”

    • value = char[] 字符串值存储的是一个字符数组
  4. 字符串的特点:不可变的字符串对象

    • ( replcace()方法 return new String() 返回新的对象 由方法的逻辑决定)
  5. 字符串常用方法:【字符串的底层是操作数组 ,char[] 】练习

    • charAt(int index) :返回下标处的字符值
    • concat(“abc”):拼接字符串
    • contains(“a”):判断是否包含
    • endWith(“d”):判断字符串后缀
    • getBytes():返回byte类型数组
    • isEmpty():判断字符串是否为空
    • length():字符串的长度
    • split(","):分割字符串,分割的依据。
      • 如果分隔符是特殊字符,通过转义字符或正则表达式。
    • trim():去除空格 (登录用户名)
    • toCharArray():字符串 --> 数组
    • String.valueOf():基本数据类型、类、数组 --> 字符串
    • substring(beginIndex, endIndex):截取
  6. null 是不指向任何字符串对象。

    "" 是空字符串,不包含任何字符,是一个对象。

    “null” ,由4个字符组成,系统作打印。


作业

  1. abstract的作用
    • 可以修饰类和方法
    • 不能修饰属性和构造方法
    • abstract 修饰的类是抽象类,需要被继承
    • abstract 修饰的方法是抽象方法,需要子类被重写
  2. 父类引用不能调用子类特有的方法。

快捷键

  1. 快速生成构造器等:右键 --> source
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值