跳至主要內容
Java - 反射3

反射3

类加载器 AppClassLoader | ExtClassLoader | BootstarpClassLoader

类加载器就是用于加载一个类的,但是类加载器并不是只有一个。

思考: 既然说Class对象和加载的类唯一对应,那如果我们手动创建一个与JDK包名一样,同时类名也保持一致,JVM会加载这个类吗?

package java.lang;

public class String {    //JDK提供的String类也是
    public static void main(String[] args) {
        System.out.println("我姓🐴,我叫🐴nb");
    }
}

codejava大约 3 分钟
Java - 注解

注解

注解可以被标注在任意地方,包括方法上、类名上、参数上、成员属性上、注解定义上等,就像注释一样,它相当于我们对某样东西的一个标记。而与注释不同的是,注解可以通过反射在运行时获取,注解也可以选择是否保留到运行时。

比如@Override表示重写父类方法(当然不加效果也是一样的,此注解在编译时会被自动丢弃)注解本质上也是一个类,只不过它的用法比较特殊。

预设注解

JDK预设了以下注解,作用于代码:

  • @Override- 检查(仅仅是检查,不保留到运行时)该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告(仅仅编译器阶段,不保留到运行时)
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。

codejava大约 5 分钟
Java - 多线程与反射3

多线程3

waitnotify 方法

Object 类还有三个方法我们从来没有使用过,分别是wait()notify()以及notifyAll()

他们其实是需要配合synchronized来使用的,平常环境下是无法使用的,只有当对象作为锁时,才能用这三个方法。

实际上锁就是依附于对象存在的,每个对象都应该有针对于锁的一些操作,所以说就这样设计了。


codejava大约 5 分钟
Java - 多线程与反射4

多线程4

守护线程

t.setDaemon(true);

  • 守护进程在后台运行运行,不需要和用户交互,本质和普通进程类似。
  • 而守护线程就不一样了,当其他所有的非守护线程结束之后,守护线程自动结束,也就是说,Java中所有的线程都执行完毕后,守护线程自动结束,因此守护线程不适合进行IO操作,只适合打打杂。
public static void main(String[] args) throws InterruptedException{
    Thread t = new Thread(() -> {
        while (true){
            try {
                System.out.println("程序正常运行中...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t.setDaemon(true);   //设置为守护线程(必须在开始之前,中途是不允许转换的)
    t.start();
    for (int i = 0; i < 5; i++) {
        Thread.sleep(1000);
    }
}

codejava大约 4 分钟
Java - 反射1

反射1

反射

反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够知道这个类所有的属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。

简而言之,我们可以通过反射机制,获取到类的一些属性,包括类里面有哪些字段,有哪些方法,继承自哪个类,甚至还能获取到泛型!它的权限非常高,慎重使用!

JAVA 类加载机制

20250310160214
20250310160214

codejava大约 5 分钟
Java - 反射2

反射2

创建类对象 getConstructor | newInstance

可以通过Class对象来创建对象、调用方法、修改变量。

  • 我们通过 newInstance() 即可创建对应的对象实例。

    通过使用newInstance()方法来创建对应类型的实例,返回泛型T,注意它会抛出InstantiationExceptionIllegalAccessException异常

    当类默认的构造方法被带参构造覆盖时,会出现InstantiationException异常,因为newInstance()只适用于默认无参构造

    当默认无参构造的权限不是public时,会出现IllegalAccessException异常,表示我们无权去调用默认构造方法

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Class<Student> clazz = Student.class;
        Student student = clazz.newInstance();
        student.test();
    }
    
    static class Student{
        public void test(){
            System.out.println("萨日朗");
        }
    }
    
  • 在JDK9之后,不再推荐使用newInstance()方法, 而是通过获取构造器 getConstructor(),来实例化对象,通过获取类的构造方法(构造器)来创建对象实例,会更加合理。 我们可以使用getConstructor()方法来获取类的权限为 public 的构造方法,同时我们需要向其中填入参数,也就是构造方法需要的类型

      public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
          Class<Student> clazz = Student.class;
          Constructor<Student> constructor = clazz.getConstructor(String.class);
          Student student = constructor.newInstance("penguin");
          student.test();
      }
    
      public class Student extends Test<String> {
        String name;
        int age;
    
        public Student(String name){
          this.name = name;
        }
    
        public void test(){
          System.out.println(this.name);
        }
      }
    
  • 当访问权限不是public的时候, 会无法找到此构造方法, 使用getDeclaredConstructor()方法可以找到类中的非public构造方法,但是在使用之前,我们需要先修改访问权限,在修改访问权限之后,就可以使用非public方法了(这意味着,反射可以无视权限修饰符访问类的内容).

      Class<Student> clazz = Student.class;
      Constructor<Student> constructor = clazz.getDeclaredConstructor(String.class);
      constructor.setAccessible(true);   //修改访问权限
      Student student = constructor.newInstance("what's up");
      student.test();
    

codejava大约 6 分钟
Java - 多线程与反射1

多线程

进程与线程概念

进程是程序执行的实体,每一个进程都是一个应用程序(比如我们运行QQ、浏览器、LOL、网易云音乐等软件),都有自己的内存空间,CPU一个核心同时只能处理一件事情,当出现多个进程需要同时运行时,CPU一般通过时间片轮转调度算法,来实现多个进程的同时运行。

20250226173747
20250226173747

codejava大约 8 分钟
Java - 多线程与反射2

多线程2

线程锁和线程同步

多线程下java内存管理

20250226223324
20250226223324

线程之间的共享变量(比如之前悬念中的value变量)存储在主内存(main memory)中,每个线程都有一个私有的工作内存(本地内存),工作内存中存储了该线程以读/写共享变量的副本。


codejava大约 6 分钟
Java - IO2

IO流2

缓冲流

虽然普通的文件流读取文件数据非常便捷,但是每次都需要从外部I/O设备去获取数据,由于外部I/O设备的速度一般都达不到内存的读取速度,很有可能造成程序反应迟钝,因此性能还不够高,而缓冲流正如其名称一样,它能够提供一个缓冲,**提前将部分内容存入内存(缓冲区)**在下次读取时,如果缓冲区中存在此数据,则无需再去请求外部设备。同理,当向外部设备写入数据时,也是由缓冲区处理,而不是直接向外部设备写入。

20250225181159
20250225181159

codejava大约 4 分钟
Java - IO3

IO流3

转换流

有时会遇到这样一个很麻烦的问题:我这里读取的是一个字符串或是一个个字符,但是我只能往一个OutputStream里输出,但是OutputStream又只支持byte类型,如果要往里面写入内容,进行数据转换就会很麻烦

public static void main(String[] args) {
    try(OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("test.txt"))){  
        //虽然给定的是FileOutputStream,但是现在支持以Writer的方式进行写入
        writer.write("lbwnb");   //以操作Writer的样子写入OutputStream
    }catch (IOException e){
        e.printStackTrace();
    }
}

codejava大约 4 分钟