集合、枚举、注解、反射

集合

我们之前存储很多数据时,最先想到的就是数组,但数组初始化以后,长度就不可变了,不便于扩展。数组中提 供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高。同时无法直接获取存储元素的 个数。数组存储的数据是有序的、可以重复的。---->存储数据的特点单一;这时就要考虑Java 集合类,可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。保存数据的时候,需要考虑使用集合。

Java 集合可分为 Collection 和 Map 两种体系。Collection接口:单列数据,定义了存取一组对象的方法 的集合List:元素有序、可重复的集合。Set:元素无序、不可重复的集合。Map接口:双列数据,保存 具有映射系“key-value对”的集合。

集合框架

集合
Collection
Map
collections
List
Set
ArrayList
LinkedList
Vector
HashSet
TreeSet
LinkedHashSet
HashMap
Hashtable
LinkedHashMap
TreeMap
Properties

在这里插入图片描述

集合主要是两组(单列集合,双列集合)

 CoLLection 接口有两个重要的子接口List和Set ,他们的实现子类都是单列集合
 Map接口的实现子类是双列集合,存放的K-V

1、Collection接口

既然Collection接口是集合中的顶层接口,那么它中定义的所有功能子类都可以使用。查阅API中描述的 Collection接口。Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序 的,而另一些则是无序的。这里我们不关心具体创建的Collection中的那个子类对象,这里重点演示的是 Collection接口中的方法。

里面可以保存Object

boolean add(E e):确保此 collection 包含指定的元素(可选操作)。

boolean addAll(Collection c):将指定 collection 中的所有元素都添加到 此collection 中(可选操作)。

void clear():移除此 collection 中的所有元素(可选操作)。

boolean contains(Object o):如果此 collection 包含指定的元素,则返回 true 。

boolean containsAll(Collection c):如果此 collection 包含指定 collection 中的 所有元素,则返回 true 。

boolean equals(Object o):比较此 collection 与指定对象是否相等。

int hashCode():返回此 collection 的哈希码值。

boolean isEmpty():如果此 collection 不包含元素,则返回 true 。

Iterator iterator():返回在此 collection 的元素上进行迭代的迭代器。

boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话(可 选操作)。 如果传进一个0的话,是看成值而不是下标

boolean removeAll(Collection c):移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。

boolean retainAll(Collection c):仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。

int size():返回此 collection 中的元素数。

Object[] toArray():返回包含此 collection 中所有元素的数组。

T[] toArray(T[] a):返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定 数组的运行时类型相同

Iterator:迭代器,集合很多,但是每种集合有自己保存数据的数据结构,使用迭代器去除集合中的元素
            先判断集合中是否有元素,如果有,取出
            hasNext:判断是否有下一个元素
            next:获取下一个元素
            remove:移除元素

●Collection接口实现类的特点
public interface Collection extends Iterable

  1. collection实现子类可以存放多个元素,每个元素可以是Object
    2)有些Collection的实现类,可以存放重复的元素,有些不可以
    3)有些Collection的实现类,有些是有序的(List), 有些不是有序(Set)
  2. Collection接口没有直接的实现子类,是通过它的子接口Set和List来
    实现的

Iterortor

在这里插入图片描述

List接口

List接口时collection接口下的一个接口

鉴于Java中数组用来存储数据的局限性,我们通常使用List替代数组。一个有序集合(也被称为序列)。 此接口的用户在列表中的每个元素都被插入的地方有精确的控制。用户可以通过它们的整数索引(在列 表中的位置)访问元素,并在列表中搜索元素。 与set不同的是,列表通常允许重复元素。

List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。

List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector。

常用方法

void add(int index, E element) :在列表的指定位置插入指定元素(可选操作)。

boolean addAll(int index, Collection c) :将指定 collection 中的 所有元素都插入到列表中的指定位置。

E get(int index) :返回列表中指定位置的元素。

int indexOf(Object o) :返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元 素,则返回 -1。

int lastIndexOf(Object o) :返回此列表中最后出现的指定元素的索引;如果列表不包含此元 素,则返回 -1。

ListIterator listIterator() :返回此列表元素的列表迭代器(按适当顺序)。 E remove(int index) :移除列表中指定位置的元素(可选操作)。

E set(int index, E element) :用指定元素替换列表中指定位置的元素(可选操作)。

List subList(int fromIndex, int toIndex) :返回列表中指定的 fromIndex (包括 )和 toIndex (不包括)之间的部分视图。

default void sort(Comparator c) :分类列表使用提供的 Comparator比较元 素。

List 实现子类

Collection接口:单列集合,用来存储一个一个的对象。

List接口:存储有序的、可重复的数据。 -->“动态”数组,替换原有的数组。

ArrayList:底层是数组,7是再创建集合的时候,10个长度的Object类型的数组就被创建了,后面扩容是原来长度的一半.循环遍历比较高
LinkedList:链表结构  Node. 插入和删除效率比较高
Vector:底层也是数组 ,古老的类,线程安全的,效率比较低 ,不常用 , 扩容是原来长度的一倍.
       即使需要使用一个 线程安全的list,也会将ArrayList做一个转换Collections.synchronizedList(list); 此时得到的集合就是一个线程安全的集合。

主要看这三个类的底层代码

ArrayList底层

构造函数:

 public ArrayList(int initialCapacity):根据这个数字创建一个长度数组,若小于0会报错

 public ArrayList():生成默认空数组

 public ArrayList(Collection<? extends E> c):会先看是不是同一个元素再依次复制

 public void trimToSize():重置大小,因为每次添加如果需要扩容的话,就是扩容1.5倍,存在空间浪费,该方法就是去掉为null的元素空间

枚举与注解

枚举

引出:

 和我们一致使用的类差不多,但平常使用的类,我们课以随便创建对象,这里的枚举就有限制,比如一个季节类,如果也可以随便创建的话,那么春天、夏天、红天、绿天…很显然不合理。

一般用两种实现方法:

 自定义类

 枚举类

自定义枚举类,利用类实现

package 枚举和注解.枚举;
//自定义实现枚举
public class Demo1 {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
    }
}
//自定义枚举
class Season{
    private String name;
    private String desc;
    //1、构造私有化
    private Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }
    //2、无set方法,因为季节不可改
    public String getName() {
        return name;
    }
    public String getDesc() {
        return desc;
    }
    //3、直接在内部创建固定对象
    public static final Season SPRING = new Season("春天", "温暖");
    public static final Season SUMMER = new Season("夏天", "炎热");
    public static final Season AUTUMN = new Season("秋天", "凉爽");
    public static final Season WINTER = new Season("冬天", "寒冷");
        //简写

    //4、重写toString
    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

枚举类

package 枚举和注解.枚举;

public class Demo2 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
        WeekDays weekDays1 = WeekDays.FRI;
        WeekDays weekDays2 = WeekDays.FRI;
        System.out.println(weekDays1 == weekDays2);//true
    }
}
//枚举类
enum Season2{
    //注意三点,和平常类的区别
    //1、class改成enum
    //2、对象创建有区别,用,间隔
    //3、对象创建在最上面
    SPRING("春天", "温暖"),
    SUMMER("夏天", "炎热"),
    AUTUMN("秋天", "凉爽"),
    WINTER("冬天", "寒冷");
    private String name;
    private String desc;
    private Season2(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }
    public String getName() {
        return name;
    }
    public String getDesc() {
        return desc;
    }
    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}
//还是上面的枚举类,如果对象还有接口需要实现呢
enum Season3 implements info{
    //注意三点,和平常类的区别
    //1、class改成enum
    //2、对象创建有区别,用,间隔
    //3、对象创建在最上面
    SPRING("春天", "温暖"){
        public void show(){
            System.out.println("");
        }
    },
    SUMMER("夏天", "炎热"){
        public void show(){
            System.out.println("");
        }
    },
    AUTUMN("秋天", "凉爽"){
        public void show(){
            System.out.println("");
        }
    },
    WINTER("冬天", "寒冷"){
        public void show(){
            System.out.println("");
        }
    };
    //可以每个对象都重写一下接口方法,当然也可以直接枚举类中实现
    private String name;
    private String desc;
    private Season3(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }
    public String getName() {
        return name;
    }
    public String getDesc() {
        return desc;
    }
    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}
interface info{
    public void show();
}
//如果将上面的枚举再简化一点呢
enum WeekDays {
    MON,TUE,WED,THR,FRI,STA,SUN;
    //这个就相当于,创建了对象,这些对象全部调用无参构造方法;
    //这样使用一般都是把里面内容当成自定义常量来使用

}

注解

1)注解(Annotation)也被称为元数据(Metadata),用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息。
2)和注释一 样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
3)在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替java EE旧版中所遗留的繁冗代码和XML配置等。

使用Annotation时要在其前面增加@符号,并把该Annotation当成一个修饰符使用。用于修饰它支持的程序元素
三个基本的Annotation:

  1. @Override:限定某个方法,是重写父类方法,该注解只能用于方法
  2. @Deprecated:用于表示某个程序元素(类,方法等)已过时
  3. @SuppressWarnings:抑制编译器警告

注:@interface不是interface,是注解类是jdk5之后加入的

@Override

这个就不举例了,我们经常遇到

1、表示重写父类方法、不一定是直接父类

2、不写@Override的话,重写方法也不会影响

3、那么@Override作用是什么呢?@Override表示接下来要重写方法,防止本来打算重写的方法写错,

比如父类中存在say方法,你本来打算重写该方法,但不小心写错了写成了see方法,如果不加@Override,那么就会把see方法当成自己的方法,不看成是重写,但如果加上@Override的话,就会报错,说明要重写的方法,并不存在。

@Deprecated

@Deprecated:用于表示某个程序元素(类,方法等)已过时

package 枚举和注解.注解;

public class Demo2 {
    A a = new A();

}
//1. @Deprecated 修饰某个元素(包、类、方法、元素、等),表示该元素已经过时
//2.即不在推荐使用,但是仍然可以使用
//3、作用:jdk版本会更新,可能有的方法现在是jdk8很流行,然后jdk升级到10了,有些方法会过时,那可以直接淘汰吗?
// 当然不行,如果直接淘汰,那么之前写的代码就会出现问题,所以就要存在过渡,不推荐用,但还是能用
@Deprecated
class A{
    public void f(){
        System.out.println(" ");
    }
}

@SuppressWarnings

@SuppressWarnings:抑制编译器警告

package 枚举和注解.注解;

import java.util.ArrayList;
import java.util.List;

public class Demo3 {
    @SuppressWarnings({"all"})//抑制所有警告,平时我们写代码,会存在很多警告不美观,直接all
    public static void main(String[] args) {
        //1. 当我们不希望看到这些警告的时候,可以使用SuppressWarnings注解来抑制警告信息
        //2. 在{""}中,可以写入你希望抑制(不显示)警告信息
        //3. 作用范围,放在main方法这里,那么只对main方法有效;当然也可以直接方法类、属性上
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        int i;
    }
}

元注E解的基本介绍
JDK的元Annotation用于修饰其他Annotation
元注解:本身作用不大,讲这个原因希望同学们,看源码时,可以知道他是干什么.
元注解的种类(使用不多,了解,不用深入研究)

  1. Retention //指定注解的作用范围,三种SOURCE,CLASS,RUNTIME
  2. Target //指定注解可以在哪些地方使用
  3. Documented //指定该注解是否会在javadoc体现
    韩顺平
  4. Inherited //子类会继承父类注解
    教育

暂时实现的注解还没有实现什么功能

反射

问题引入:

 现在给你一个文件,里面写了一个类的全路径,和这类的相关方法,现在需要你创建这个类的对象,并调用这个方法;

 根据我们以前学的内容直接new 类名();但不在同一路径下的类显然不能直接创建对象;

 可能又会想到,可以把类的路径读出来,然后根据这个路径new对象,但读到的内容是一个字符串,可以用字符串直接new对象吗?显然不行

 那怎么办呢?这就需要我们今天的学习内容。可能暂时不知道为啥会有这样的问题,但学到后面的框架时,这样的问题将会很多。

快速入门

接下来根据上面的需求,实现以下代码,先体验一下

package 反射;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Cat {
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void sing(){
        System.out.println("喵喵喵");
    }
}
//假设只给你一个文件里面有这个类的绝对路径,以及相关方法,让你创建这个类,怎么办?
/*
首先把相关信息读出来,这部分就不演示了,直接给出
classPath = "反射.Cat.java"
method = "eat"
 */
class Test{
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        String classPath = "反射.Cat";
        String methodName = "eat";
        //(1) 加载类,返回Class类型的对象cls
        Class cls = Class.forName (classPath);//这里可能存在字符串读不出类,所以需要抛异常
        //(2) 通过cls得到你加载的类反射.Cat.java 的对象实例
        Object o = cls.newInstance();//抛异常
        System.out.println("o的运行类型=" + o.getClass()); //运行类型
        //(3) 通过cls得到你加载的类反射.Cat.java 的methodName"eat" 的方法对象
        //即:在反射中,可以把方法视为对象( 万物皆对象)
        Method method1 = cls.getMethod (methodName) ;
        //(4) 通过method1 调用方法:即通过方法对象来实现调用方法
        System.out.println("=============================") ;
        method1.invoke(o); //传统方法对象。方法(),反射机制方法。invoke(对象)
        //如果需要调用这个类中的其他方法,也不用修改代码,直接在信息文件中修改即可
		//这里存在很多注释,实现的话也就时4步
    }
}

反射机制

1.反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象) ,这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射

可能大家对Class类感觉很奇怪,这里没啥奇怪的,就和我们平常接触到的类时一样的,比如Math、Arrays…,只不过这个类的名字很奇怪;

就像是他的名字叫张三,你的名字叫李四,我的名字就叫名字,诶你说气不气

图解
在这里插入图片描述

反射相关的主要类:

  1. java.lang.Class:代表一 个类,Class对象表示某个类加载后在堆中的对象
  2. java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
  3. java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
  4. java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Cat {
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void sing(){
        System.out.println("喵喵喵");
    }
}
class Test{
    public static void main(String[] args) throws Exception{
        String classPath = "反射.Cat";
        String methodName = "eat";
        //加载类,返回Class类型的对象cls
        Class cls = Class.forName (classPath);//这里可能存在字符串读不出类,所以需要抛异常
        //通过cls得到你加载的类反射.Cat.java 的对象实例
        Object o = cls.newInstance();//抛异常
        System.out.println("o的运行类型=" + o.getClass());
        //得到方法
        Method method1 = cls.getMethod (methodName) ;
        method1.invoke(o); //调用方法
        //得到成员变量,getField不能得到私有的属性
        Field nameField = cls.getField("age"); //
        System.out.println(nameField.get(o)); //调用变量
        //构造方法
        Constructor constructor = cls.getConstructor() ;//里面可以传参数,不传参数得到的就是无参构造方法
        System.out.println(constructor);


    }
}

反射优点和缺点
1.优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
2.缺点:使用反射基本是解释执行,对执行速度有影响.

那么怎么优化呢? 反射调用优化+关闭访问检查

●反射调用优化关闭访问检查

  1. Method和Field、 Constructor对象都有setAccessible(方法
  2. setAccessible作用是启动和禁用访问安全检查的开关
    3.参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值
    为false则表示反射的对象执行访问检查

 以调用方法为例,只需要在Method method1 = cls.getMethod (methodName) ;时,再加一句method1.setAccessible(true);但并不会优化很多,和我们以前调用方法还是差了很多

  1. Class也是类,因此也继承Object类[类图]
  2. Class类对象不是new出来的,而是系统创建的[演示]
  3. 对于某个类的Class类对象, 在内存中只有一份,因为类只加载一 次[演示]
    4.每个类的实例都会记得自己是由哪个Class实例所生成
    5.通过Class对象可以完整地得到一个类的完整结构,通过一系列API
  4. Class对象是存放在堆的
    7.类的字节码二进制数据,是放在方法区的,
    有的地方称为类的元数据(包括方法代码,
    变量名,方法名,访问权限等等) https:/ /www.zhihu.com/question/38496907

在这里插入图片描述

常用方法

package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Cat {
     public String name = "花花";
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void sing(){
        System.out.println("喵喵喵");
    }
}
class Test{
    public static void main(String[] args) throws Exception{

        String classPath = "反射.Cat";
        //1。获取到Car类对应的Class对象
        //<?>表示不确定的Java类型
        Class<?> cls = Class.forName (classPath) ;
        //2. 输出cLs
        System.out.println(cls); // 显示cls对象,是哪个类的Class对象 反射.Cat
        System.out.println(cls.getClass()); //输出cLs运行类型java.Lang.Class
        //3. 得到包名
        System.out.println(cls.getPackage().getName());//包名
        //4.得到全类名
        System.out.println(cls. getName());
        //5. 通过cLs创建对象实例
        Cat cat = (Cat)cls.newInstance() ;
        System.out.println(cat);
        //6.通过反射获取属性brand
        Field brand = cls. getField("name");
        System.out.println(brand.get(cat));//花花
        //7.通过反射给属性赋值
        brand.set(cat, "小白");
        System.out.println(brand.get(cat));//小白
        //8我希望大家可以得到所有的属性(字段)
        Field[] fieLds = cls.getFields();//得到所有的变量名
        for (Field f : fieLds) {
            System.out.println(f.getName());//名称
        }




    }
}

获取class类对象的方式

package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Cat {
     public String name = "花花";
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void sing(){
        System.out.println("喵喵喵");
    }
}
class Test{
    public static void main(String[] args) throws Exception {
        //1、Class.forName()就是上面的例子  多用于配置文件,读取类全路径,加载类.  编译阶段
        String classPath = "反射.Cat";
        Class<?> cls1 = Class.forName(classPath);
        System.out.println(cls1);

        //2、类名.class  多用于参数传递,比如通过反射得到对应构造器对象.  加载阶段
        Class cls2 = Cat.class;
        System.out.println(cls2);

        //3、对象.getClass()  通过创建好的对象,获取Class对象.  运行阶段
        Cat cat = new Cat();
        Class cls3 = cat.getClass();
        System.out.println(cls3);

        //4. 通过类加载器[4种]来获取到类的CLass对象
        //(1)先得到类加载器car
        ClassLoader classLoader = cat.getClass().getClassLoader() ;
        //(2)通过类加载器得到CLass对象
        Class cls4 = classLoader.loadClass (classPath);
        System.out.println(cls4);

        //cls1、cls2、cls3、cls4 其实是同一个对象
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        System.out.println(cls3.hashCode());
        System.out.println(cls4.hashCode());

        //5.基本数据(int, char, booLean, float , double, byte, long, short) 按如下方式得到Class类对象
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        Class<Boolean> booLeanCLass = boolean.class;
        System.out.println(integerClass);//int
        //6.基本数据类型对应的包装类,可以通过.TYPE 得到CLass类对象
        Class<Integer> type1 = Integer. TYPE;
        Class<Character> type2 = Character. TYPE;
        System.out.println(type1);
        System.out.println(integerClass.hashCode());//?
        System.out.println(type1.hashCode());//?  相等 




    }
}

哪些类型有class对象

1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2。interface :接口
3.数组

4enum :枚举
5.annotation :注解
6.基本数据类型

7void

package 反射;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Cat {
     public String name = "花花";
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void sing(){
        System.out.println("喵喵喵");
    }
}
class Test{
    public static void main(String[] args) throws Exception {
        Class<String> cls1 = String.class;//外部类
        Class<Serializable> cls2 = Serializable.class;//接口
        Class<Integer[]> cls3 = Integer[].class;//数组
        Class<float[][]> cls4 = float[][].class;//二维数组
        Class<Deprecated> cls5 = Deprecated.class;//注解
        //枚举
        Class<Thread.State> cls6 = Thread.State.class;
        Class<Long> cls7 = Long.class;//基本数据类型
        Class<Void> cls8 = void.class;//void数据类型
        Class<Class> cls9 = Class.class;//类

        System.out.println(cls1);
        System.out.println(cls2);
        System.out.println(cls3);
        System.out.println(cls4);
        System.out.println(cls5);
        System.out.println(cls6);
        System.out.println(cls7);
        System.out.println(cls8);
        System.out.println(cls9);




    }
}

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强(new 类)
2.动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性(forName)

●类加载时机
1.当创建对象时(new) //静态加载
2.当子类被加载时,父类也加载//静态加载
3.调用类中的静态成员时//静态加载
4.通过反射//动态加载
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值