1. List接口以及他的常用实现类

1.1 List接口

有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。

  • ```java
    public interface Listextends Collection
    1
    2
    3
    4
    5
    6
    7

    #### 1.2 `ArrayList`

    继承自 `AbstractList`,实现了 List 接口。底层基于数组实现容量大小动态变化。允许 null 的存在。同时还实现了 `RandomAccess`、`Cloneable`、`Serializable` 接口,所以`ArrayList` 是支持快速访问、复制、序列化的。

    ```java
    List<Integer> list = new ArrayList<>();//实现类

1.3 常用方法

  • | boolean | add(E e) 将指定的元素追加到此列表的末尾。 |
    | :—————-: | :—————————————————————————————: |
    | void | add(int index, E element) 在此列表中的指定位置插入指定的元素。 |
    | void | clear() 从列表中删除所有元素。 |
    | E | get(int index) 返回此列表中指定位置的元素。 |
    | Iterator<E> | iterator() 以正确的顺序返回该列表中的元素的迭代器。 |
    | E | remove(int index) 删除该列表中指定位置的元素。 |
    | int | size() 返回此列表中的元素数。 |
    | Object[] | toArray() 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。 |

1.4 底层实现

  • ArrayList 底层是基于数组来实现容量大小动态变化的。默认初始容量大小为 10。是线程不同步的

  • 扩容:第一次扩容10,以后每次都扩容原容量的1.5倍,扩容通过位运算右移动1位。

  • ```java
    List list = new ArrayList<>();//实现类
    /**

    • Default initial capacity.
      */
      private static final int DEFAULT_CAPACITY = 10;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    - 遍历方式:for循环,增强for, 迭代器。

    #### 1.5 `LinkedList`

    `LinkedList`: `LinkedList` 实现 List 接口,能对它进行[队列](https://so.csdn.net/so/search?q=队列&spm=1001.2101.3001.7020)操作。`LinkedList` 是通过双向链表去实现的。

    - ```java
    List<Integer> list = new LinkedList<>();//实现类
    //栈(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。
    //队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

1.6 面试题:ArrayListLinkedList 的区别?

都是线程不同步的。

ArrayList:

  • 基于动态数组的数据结构
  • 对于随机访问的get和set,其效率优于LinkedList
  • 对于随机操作的add和remove,ArrayList不一定比LinkedList慢(ArrayList底层由于是动态数组,因此并不是每一次add和remove都需要创建新数组)

LinkedList

  • 基于链表的数据结构

  • 对于顺序操作,LinkedList 不一定比ArrayList

  • 对于随机操作,LinkedList 效率明显低于LinkedList

  • 内部是基于链表结构实现的。添加和删除比较快,查询相对ArrayList比较慢.

    内部相对于ArrayList而言多了一些操作头和尾的方法。可以充当队列,堆栈。不是线程安全的(同步的)。

2.HashSetTreeSet

  • 都实现了Set接口,集合中存储的元素不重复。
  • 都是无序的

2.1 HashSet实现原理

  • 此类实现Set接口,由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证; 特别是,它不能保证订单在一段时间内保持不变。 这个类允许null元素。
  • 去重:根据判断每个元素的hashCode值是否相同和equals是否为true判断此元素是否相同
  • 如果两个对象的hashCode相等 并且 两个对象调用equals结果是true 才认为两个元素重复

2.2 TreeSet 实现原理

  • ```java
    TreeSet set = new TreeSet<>();
    //构造方法
    TreeSet(Comparator<? super E> comparator) //构造一个新的,空的树集,根据指定的比较器进行排序。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    - 介绍:1.无序:不保证(不记录)我们的添加顺序;

    2.不重复:不能够添加重复元素

    3.内部存储有一定的顺序

    ***\*注意:`TreeSet`一旦添加了第一个元素后就不能添加其它数据类型的元素了,只能添加相同数据类型的元素,除非将容器中所有的元素全部清空,才能添加新的数据类型的元素\****

    #### 2.3 自然排序和定制排序

    - 自然排序:实现Comparable接口,重写此方法,返回值为0表示元素相同,负整和正整数数表示倒序或顺序。

    ```java
    @Override
    public int compareTo(Object o) {
    //自定义逻辑
    return 0;
    }

定制排序:实现Comparator(比较器)接口,重写此方法,返回值为0表示元素相同,负整和正整数数表示倒序或顺序。

1
2
3
4
@Override
public int compare(Object o1, Object o2) {
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
if(o1==null||o2==null){//判断,若两个有一个为null都直接返回
return 0;
}
if(o1 instanceof Student && o2 instanceof Student){//如果类型匹配才转换
Student stu1 = (Student)o1;
Student stu2 = (Student)o2;
if(stu1.age>stu2.age){//先判断年龄后判断姓名
return 1;
}else if(stu1.age<stu2.age){
return -1;
}else{
return stu1.name.compareTo(stu2.name);
}
}
return 0;
}
}

//MyComparator mc = new MyComparator();
//TreeSet ts = new TreeSet(mc);
  • 1

3. IO流

3.1 InputStream

  • 字节输入流读取文件一般用于图片,视频等文件

1
2
3
4
InputStream in = new FileInputStream(File file);
InputStream in = new FileInputStream(String pathname);
//缓冲流
BufferedInputStream buff = new BufferedInputStream(in);

3.2 FileReader

  • 字符输入流一般用于读取文字
1
2
3
4
FileReader reader=new FileReader(File file);
FileReader reader=new FileReader(String pathname);
//字符缓冲流
BufferedReader buff = new BufferedReader(reader);

3.3 OutputStream

  • 字节输出流写出文件一般用于图片,视频等文件

  • ```java
    OutputStream out = new FileOutputStream (File file);
    OutputStream out = new FileOutputStream (String pathname);
    //缓冲流
    BufferedOutputStream buff = new BufferedOutputStream(out);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    #### 3.4 `FileWriter`

    - 字符输出流一般用于写出文字

    - ```java
    FileWriter writer=new FileWriter(File file);
    FileWriter writer=new FileWriter(String pathname);
    //字符缓冲输出流
    BufferedWriter buff = new BufferedWriter(writer);

3.5 复制文件案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.lqs.ioTest;

import java.io.*;

@SuppressWarnings("all")
public class CopyAllVideoContent {
public static void main(String[] args) {
copyFile();
//递归复制所有文件
/* File file = new File("E:\\itsourse\\2022-07-02-JAVA加强-集合-Map-泛型");
copyAllVideoContents(file, "E:\\itsourse\\copyVideo");*/
}

/**
* 在file中查找以.mp4的文件并复制到指定位置
*/
public static String copyAllVideoContents(File file, String dir) {
if (!file.exists() || file.listFiles().length == 0) {
return "文件不存在或文件无内容!";
}
File[] files = file.listFiles();
for (File f : files) {
if (f.isFile()) {
//复制视频文件
copyVideoFile(f, dir);
} else {//目录 递归调用
copyAllVideoContents(f, dir);
}
}
return "复制视频内容完成!!!";
}

private static void copyVideoFile(File f, String dir) {
if (f.getName().endsWith("mp4")) {
try (//自动关流
InputStream in = new FileInputStream(f);
OutputStream out = new FileOutputStream(dir + "\\" + f.getName());
) {
int count;
byte[] bytes = new byte[1024];
while ((count = in.read(bytes, 0, bytes.length)) != -1) {
out.write(bytes, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println("未拷贝文件名称:" + f.getName());
}
}


/**
* 采用字节缓冲流复制 提高效率
*/
public static void copyFile() {
File file = new File("E:\\itsourse\\预习视频-有声版\\2022-03-29-JAVA-Map和泛型\\video");
File[] files = file.listFiles();
for (File f : files) {
copyByBuffered(f);
}

System.out.println("复制完成");
}

private static void copyByBuffered(File f) {
final File file = new File("E:\\itsourse\\mapVideo");
if (!file.exists()) {
file.mkdirs();
}
try (
InputStream in = new FileInputStream(f);
BufferedInputStream buf = new BufferedInputStream(in);
OutputStream out = new FileOutputStream("E:\\itsourse\\mapVideo" + "\\" + f.getName());
BufferedOutputStream bufout = new BufferedOutputStream(out);
) {
int count;
byte[] bytes = new byte[1024];
while ((count = buf.read(bytes, 0, bytes.length)) != -1) {
bufout.write(bytes, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

3.6 RandomAccessFile

  • 随机访问流读写文件,一般用于下载文件。

    | void | setLength(long newLength) 设置此文件的长度。 |
    | :——: | :—————————————————————————————: |
    | void | seek(long pos) 设置文件指针偏移,从该文件的开头测量,发生下一次读取或写入。 |

  • ```java
    /**

    • 随机访问流读取文件
      */
      public class RandomStreamTest {
      public static void main(String[] args) throws Exception {

       String thisLine = null;
       RandomAccessFile as = new RandomAccessFile("E:\\javabase\\practiceDemo\\src\\com\\lqs\\ioTest\\song.txt", "rw");
       System.out.println(as.length());
       int count;
       byte[] bytes = new byte[1024];
       while ((count = as.read(bytes, 0, bytes.length)) != -1) {
           System.out.print(new String(bytes, 0, count));
       }
       as.setLength(1024 * 1024 * 8);//设置文件大小为8M
       as.seek(1024);//设置偏移量
      

      /* while ((thisLine = as.readLine()) != null) {

           System.out.println(thisLine);
       }*/
      

      }
      }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43



      ### 4. 自定义日期转换工具类

      ```java
      package com.lqs.utils;

      import java.text.ParseException;
      import java.text.SimpleDateFormat;
      import java.util.Date;
      @SuppressWarnings("all")
      public class DateUtils {
      /**
      * 字符转日期
      *
      * @param s
      * @return
      */
      public static Date stringToDate(String s) {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
      Date date = null;
      try {
      date = sdf.parse(s);
      } catch (ParseException e) {
      e.printStackTrace();
      }
      return date;
      }

      /**
      * 日期转字符
      * @param date
      * @return
      */
      public static String dateToString(Date date) {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
      String s = null;
      s = sdf.format(date);
      return s;
      }
      }

5. 设计模式

5.1 单例设计模式

  • 单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
  • 单例特征:①对象构造私有化,②私有静态当前类类型的字段,③提供公共,静态对外的访问方法获取对象

5.2 饿汉模式

  • 实质上就是在类加载的时候即创建,

    饿汉模式线程安全,但是存在加载效率低下的问题,

    使用静态内部类块优化。

  • ```java
    /**

    • 单例设计模式
    • 1.构造方法私有化
    • 2.初始化成员属性
      */
      public class SingleInstance {
      private static SingleInstance instance = new SingleInstance();//饿汉单例模式

      private SingleInstance() {
      }

      public static SingleInstance getInstance() {

       return instance;
      

      }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11

      - ```java
      /**
      * 饿汉单例模式
      * 一开始就初始化对象
      */
      @Test
      public void testInstance() {//同一个对象
      System.out.println(SingleInstance.getInstance());
      System.out.println(SingleInstance.getInstance());
      }

5.3 懒汉模式

  • 即在需要的时候才创建对象返回,懒汉模式容易造成线程不安全问题,故可以同步代码块【synchronized】解决线程问题,但要使用双重校验,而且同步代码块这种方式效率比较低。

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.lqs.utils;

    /**
    * 单例设计模式
    * 1.构造方法私有化
    * 2.初始化成员属性
    */
    public class SingleInstance2 {
    //volatile 保证AB线程会看到变量instance的同一个值
    private static volatile SingleInstance2 instance = null;//懒汉单例模式 会出现线程安全问题 需要解决

    private SingleInstance2() {
    }

    public static SingleInstance2 getInstance() {
    if (instance == null) {//防止多线程排队
    synchronized (SingleInstance2.class) {//同步锁 线程进来需要排队 但是每一个线程进来都需要进行判断导致访问缓慢所以要-->防止多线程排队
    if (instance == null) {//防止多个线程排队造成 对象重复创建
    //睡眠 会出现线程安全问题
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    instance = new SingleInstance2();
    }
    }
    }
    return instance;
    }
    }

  • 测试:

    1
    2
    3
    4
    5
    6
    7
    8
    public static void main(String[] args) {
    System.out.println("=======线程安全问题========");
    new Thread(() -> {
    System.out.println(SingleInstance2.getInstance());
    }).start();
    new Thread(() -> System.out.println(SingleInstance2.getInstance())).start();//同一对象
    new Thread(() -> System.out.println(SingleInstance2.getInstance())).start();
    }

5.3 枚举单例模式(推荐)

  • ```java
    package com.lqs.utils;

    public enum MyEnum {

    MAN,//表示一个对象
    WOMAN;
    public void show() {
        System.out.println("枚举单例设计模式,设计安全哦");
    }
    

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9

    - 调用:

    ```java
    @Test
    public void testEnum() {
    MyEnum.MAN.show();//枚举单例设计模式,设计安全哦
    System.out.println(MyEnum.WOMAN);//WOMAN
    }

5.3 装饰者模式

  • 装饰模式指的是在不必改变原类文件和不使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
  • 实现步骤 :通过对原类文件继承,对原有方法功能的基础上,实现新的功能.

5.4 简单工厂模式

  • 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。(spring反射)
  • 实现步骤:使用工厂对象,根据传递的参数创建对象 解耦(耦合)\低耦合高内聚**

5.5 适配器模式

  • 适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

6. 资源文件解析

6.1 概诉

  • 资源文件也可以看成是配置文件,一般的形式有两种:properties形式和XML形式。

  • properties文件中数据的存储是\以键值对的形式存在,每一行为一条数据,只能存储字符串形式的数据,Properties文件中值的部分任意字符都会被当做值的一部分,尤其是空格**

6.2 Properties类语法

  • load(字节输入流) 加载资源文件

    getProperty(key) 返回资源文件中对应key中的值【字符串】,若key不存在则返回null

    getProperty(key,默认值) 返回资源文件中对应key中的值【字符串】,若key不存在则返回默认值

  • 传统IO方式:

    1
    2
    Properties properties = new Properties();
    properties.load(new FileInputStream(文件路径));

6.3 类加载器获取流

  • 通过类加载器获取流,那么首要是获取到类加载器,获取类加载器的方式有很多种,以下介绍两种:

    • 字节码对象方式获取类加载器—>>字节码对象.getClassLoader()

    • 线程方式获取类加载器—>>线程方式获取类加载器稍微比字节码对象获取类加载器稍显复杂,必须先获取当前线程,通过当前线程获取类加载器Thread.currentThread().getContextClassLoader()

    • 获取流语法:类加载器对象.getResourceAsStream(包名/文件名),类加载器获取流的时候,路径最前方不需要书写/

6.4 代码案例

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void testProperties() {
Properties ps = new Properties();
// InputStream in = TestAll.class.getClassLoader().getResourceAsStream("db.properties");//类加载器
try {
ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));//读取文件
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(ps);
System.out.println(ps.getProperty("username"));
System.out.println(ps.getProperty("password"));
}

7. 注解

7.1 jdk四大内置注解

  1. @Override

    • 作用:检查方法是否方法覆写
    • 位置:方法@Deprecated
  2. @Deprecated

    • 作用:用来标记过时,过时不是不可以用,只是不建议使用

    • 过时:后面的版本可能不维护升级,已经有更好的替换方案

  3. @SuppressWarings

    • 作用:抑制警告,不建议使用,注解可以传值
    • @SuppressWarings("all")
  4. @SafeVarargs

    • 作用:抑制堆污染警告,这个注解是后面才出来的,以前也是使用@SuppressWarings解决警告问题

    • 堆污染 :不建议使用

7.2 元注解:用来定义注解的注解

  1. @Target
    • 用来定义【注解】的使用位置
  2. @Retention
    • 用来定义【注解】生命周期
    • 白话:@Retention 标注在@Override ,Override这个注解的声明周期属于哪个阶段
    • RetentionPolicy
    • SOURCE:源码阶段,编译为字节码以后 注解就不存在了
    • CLASS:字节码阶段,运行注解就不存在了
    • RUNTIME:运行时,一直存在
  3. @Documented
    • 所标注的【注解】在生成文档以后,在文档中体现出来
  4. @Inherited
    • 所标注的【注解】具有继承性
    • 例如 :
    • 定义了一个注解 @VIP,在定义@VIP的时候使用了@Inherited注解
    • @VIP
    • class A{}
    • class B extends A{}
    • B这个类也能继承@VIP这个注解

7.3 注解的传值

  1. 注解的传值:@注解名字(属性名=值,属性名=值)。

  2. 特殊情况:

    • 如果属性有默认值,在使用注解的时候可以不用传值【如果没有默认值,必须传值】
    • 如果只传一个值,并且属性的名字叫做value,属性名可以省略不写
    • 数组的传值 属性名={值1,值2,值3,…}
  3. ```java
    package com.lqs.reflect;

    import com.lqs.examination.TransRecord;

    @Deprecated//表示类过期了不建议使用
    @VIP(number = “00001”, order = {1, 2, 3, 4, 5, 6, 7, 8, 9}, value = “hello”)
    public class Person {

    @Deprecated
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Deprecated
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    4. ```java
    package com.lqs.reflect;

    import java.lang.annotation.*;

    @Target(value = {ElementType.METHOD, ElementType.TYPE})//使用范围
    @Documented//是否生成文档
    @Retention(RetentionPolicy.RUNTIME)//生命周期
    @Inherited//注解的继承
    public @interface VIP {
    String value();
    //定义属性
    String name() default "coderyeah";

    String number() default "1001";

    int[] order();//数组
    }

8. 反射

8.1 概念

一个Class对象就是表示一个class文件,获取Class对象不能通过new的方式,因为只有java源程序编译后生成字节码文件,再通过class文件得到Class对象。

  1. 会产生class文件的类型有:类,接口,枚举,注解

  2. 获取Class对象:

    • 对象.getClass() Object提供

    • Class.forName(String className) Class 提供

    • 类名.class

8.2 获取Class对象

  1. ```java
    package com.lqs.reflect;

    public class User {

    private String name;
    public Long id;
    private String password;
    
    public void eat(String name) {
        System.out.println(name + "想吃大闸蟹······");
    }
    
    private void show(String name, int age) {
        System.out.println(name + "今年" + age + "岁啦");
    }
    
    //构造器开始
    public User() {
    }
    
    private User(String name, Long id, String password) {
        this.name = name;
        this.id = id;
        this.password = password;
    }
    //构造器开始
    
    public User(String name) {
        this.name = name;
    }
    //构造器结束
    
   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public Long getId() {
       return id;
   }

   public void setId(Long id) {
       this.id = id;
   }

   public String getPassword() {
       return password;
   }

   public void setPassword(String password) {
       this.password = password;
   }

   @Override
   public String toString() {
       return "User{" +
               "name='" + name + '\'' +
               ", id=" + id +
               ", password='" + password + '\'' +
               '}';
   }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

#### 8.3 通过反射获取构造方法

1. User类

```java
package com.lqs.reflect;

public class User {
private String name;
public Long id;
private String password;

//构造器开始
public User() {
}

private User(String name, Long id, String password) {
this.name = name;
this.id = id;
this.password = password;
}
//构造器开始

public User(String name) {
this.name = name;
}
//构造器结束

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", password='" + password + '\'' +
'}';
}
}

  1. 获取构造器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     @Test
    public void testGetConstructor() throws Exception {
    final Class<?> cla = Class.forName("com.lqs.reflect.User");
    final Constructor<?>[] cons = cla.getConstructors();//获取所有的public修饰的构造器
    for (Constructor<?> c : cons) {
    // System.out.println(c);//public com.lqs.reflect.User(java.lang.String),public com.lqs.reflect.User()
    }

    final Constructor<?>[] constructors = cla.getDeclaredConstructors();//获取User中所有的构造器
    for (Constructor<?> constructor : constructors) {
    // System.out.println(constructor);//包括私有的构造方法
    }
    //获取指定参数类型的公共构造器
    System.out.println(cla.getConstructor());//public com.lqs.reflect.User()
    System.out.println(cla.getConstructor(String.class));//public com.lqs.reflect.User(java.lang.String)
    //获取指定参数的私有构造器 private com.lqs.reflect.User(java.lang.String,java.lang.Long,java.lang.String)
    System.out.println(cla.getDeclaredConstructor(String.class, Long.class, String.class));
    }
  2. 使用构造方法创建对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Test
    public void testNewInstance() throws Exception {//使用构造方法创建对象
    Class<?> cla = Class.forName("com.lqs.reflect.User");
    Object newInstance = cla.newInstance();//默认使用无参构造
    System.out.println(newInstance);//User{name='null', id=null, password='null'}

    //私有构造方法
    Constructor<?> constructor = cla.getDeclaredConstructor(String.class, Long.class, String.class);
    constructor.setAccessible(true);//让权限检查失效
    Object o = constructor.newInstance("coderyeah", 10001l, "root");
    System.out.println(o);//User{name='coderyeah', id=10001, password='root'}

    //公共构造方法
    final Constructor<?> con = cla.getConstructor(String.class);
    System.out.println(con.newInstance("山姆"));//User{name='山姆', id=null, password='null'}
    }

8.4 使用反射获取方法并调用

  1. 获取方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     @Test
    public void testGetMethod() throws Exception {
    final Class<?> cla = Class.forName("com.lqs.reflect.User");
    final Method[] methods = cla.getMethods();//获取所有公共的方法,包括父类所继承的方法
    // System.out.println(methods.length);//16
    for (Method m : methods) {
    // System.out.println(m);
    }

    final Method[] declaredMethods = cla.getDeclaredMethods();//获取User类所有的方法,不包括父类所继承的方法
    // System.out.println(declaredMethods.length);//9
    for (Method method : declaredMethods) {
    // System.out.println(method);
    }
    //获取公共的指定方法名和参数类型的方法
    //public void com.lqs.reflect.User.eat(java.lang.String)
    System.out.println(cla.getMethod("eat", String.class));
    /*
    获取私有的指定方法名和参数类型的方法
    private void com.lqs.reflect.User.show(java.lang.String,int)
    */
    System.out.println(cla.getDeclaredMethod("show", String.class, int.class));

    }
  2. 获取方法并调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * 获取方法并调用:
    * Method
    * Object invoke(Object obj, Object... args) 执行方法
    * obj:调用方法的对象
    * args:调用方法的实参
    */
    @Test
    public void testInvoke() throws Exception {
    final Class<?> cla = Class.forName("com.lqs.reflect.User");
    final Method method = cla.getMethod("eat", String.class);
    method.invoke(cla.newInstance(), "coderyeah");//coderyeah想吃大闸蟹······

    //调用私有方法
    final Method show = cla.getDeclaredMethod("show", String.class, int.class);
    show.setAccessible(true);//让权限检查失效
    show.invoke(cla.newInstance(), "coderyeah", 21);//coderyeah今年21岁啦

    System.out.println(cla.getModifiers());//1 public
    System.out.println(show.getModifiers());//2 private
    }

8.5获取字段并赋值

  1. 获取字段并赋值

    • Field getField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。
      Field[] getFields() 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。

      Field getDeclaredField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。
      Field[] getDeclaredFields() 返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。

  2. ```java
    package com.lqs.reflect;

    import org.junit.Test;

    import java.lang.reflect.Field;

    public class FieldTest {

    @Test
    public void testGetField() throws Exception {
        final Class<?> cla = Class.forName("com.lqs.reflect.User");
        final Field name = cla.getDeclaredField("name");
        System.out.println(name);//private java.lang.String com.lqs.reflect.User.name
        System.out.println(cla.getField("id"));//public java.lang.Long com.lqs.reflect.User.id
        for (Field field : cla.getFields()) {
            System.out.println(field);//public java.lang.Long com.lqs.reflect.User.id
        }
    
        /**
         * private java.lang.String com.lqs.reflect.User.name
         * public java.lang.Long com.lqs.reflect.User.id
         * private java.lang.String com.lqs.reflect.User.password
         */
        for (Field field : cla.getDeclaredFields()) {
            System.out.println(field);
        }
    
    }
    
    @Test
    public void Test2() throws Exception {
        final Class<?> cla = Class.forName("com.lqs.reflect.User");
        final Field id = cla.getField("id");
        final User user = new User();
        id.set(user, 110L);
        System.out.println(id.get(user));//110
    
        final Field name = cla.getDeclaredField("name");
        name.setAccessible(true);
        name.set(user, "coderyeah");
        System.out.println(name.get(user));//coderyeah
    }
    

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    #### 8.6 使用反射创建任意对象

    1. ```java
    package com.lqs.reflect;

    public class BeanFactory {
    public static Object CreateBean(String cla) throws Exception {
    final Class<?> aClass = Class.forName(cla);
    return aClass.newInstance();
    }

    public static <T> T CreateBean(Class<T> cla) throws Exception {
    return cla.newInstance();
    }


    }

  3.     @Test
        public void testBean() throws Exception {
            final Object o = BeanFactory.CreateBean("com.lqs.reflect.User");
            System.out.println(o);//User{name='null', id=null, password='null'}
    
            System.out.println(BeanFactory.CreateBean(Student.class));//com.lqs.reflect.Student@ba8a1dc
        }