线程的第三种创建方式

  1. package com.qfedu.test1;
  2. import java.util.concurrent.Callable;
  3. import java.util.concurrent.ExecutionException;
  4. import java.util.concurrent.FutureTask;
  5. //1.创建Callable接口的实现类 <v>泛型 控制重写方法的返回值类型
  6. class MyThread implements Callable<String>{
  7. //2.重写call方法
  8. @Override
  9. public String call() throws Exception {
  10. // TODO Auto-generated method stub
  11. System.out.println(Thread.currentThread().getName() + "实现callable");
  12. return "返回值";
  13. }
  14. }
  15. public class Demo1 {
  16. public static void main(String[] args) throws InterruptedException, ExecutionException {
  17. //3.实例化Callable的实现类MyThread
  18. MyThread myThread = new MyThread();
  19. //4.将对象给FutureTask去执行
  20. //线程池知识 后面会讲
  21. //FutureTask实现了Future,Runnable接口
  22. FutureTask<String> task = new FutureTask<String>(myThread);
  23. //所以在开启一个任务 aaaaaa接下面注释
  24. FutureTask<String> task1 = new FutureTask<String>(myThread);
  25. Thread thread = new Thread(task,"线程1");
  26. Thread thread1 = new Thread(task1,"线程2");
  27. //开启的两个线程,却只打印了一个,因为结果被缓存了
  28. //异步任务,等待、运行、完成这几个状态。当一个线程处理的是同一个任务的时候task
  29. //自动返回完成状态,下面线程在执行的时候,会把它当成已经完的任务,所以不在执行
  30. //所以在开启一个任务 aaaaaa
  31. thread.start();
  32. thread1.start();
  33. System.out.println(task.get());
  34. }
  35. }

一、反射

平时获取对象,new一个对象。现在反着来,通过反射获取对象。

入门案例

1.Person

  1. package com.qfedu.test2fanshe;
  2. public class Person {
  3. String name;
  4. int age;
  5. public Person() {
  6. }
  7. public Person(String name, int age) {
  8. this.name = name;
  9. this.age = age;
  10. }
  11. @Override
  12. public String toString() {
  13. return "Person [name=" + name + ", age=" + age + "]";
  14. }
  15. }

2.Demo1

  1. package com.qfedu.test2fanshe;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.InvocationTargetException;
  4. //反射
  5. public class Demo1 {
  6. public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
  7. //正常方式获取对象
  8. Person person = new Person();
  9. person.name = "a a";
  10. System.out.println(person.name);
  11. //反射入门案例
  12. //Person.class 看成一个对象
  13. Class<?> aClass = Class.forName("com.qfedu.test2fanshe.Person");
  14. // Class<?> aClass = Person.class;
  15. //获取无参构造 Constructor(构造方法)是Person类下面的无参构造对象
  16. Constructor<?> constructor = aClass.getConstructor(null);
  17. Constructor<?> constructor1 = aClass.getConstructor(String.class,int.class);
  18. //实例化 Instance(实例)
  19. Person person1 = (Person)constructor.newInstance(null);
  20. Person person2 = (Person)constructor1.newInstance("博儿",23);
  21. person1.name = "奥斯卡";
  22. person1.age = 16;
  23. System.out.println(person1);
  24. System.out.println(person2);
  25. /*
  26. * 1.获取Class对象(类的字节码文件) Person.class里面有构造方法,属性,方法
  27. * 2.通过Class对象获取Constructor(构造方法)对象
  28. * 3.通过构造方法对象创建对象
  29. */
  30. }
  31. }

1.获取class对象

为什么要获取class对象?相当于获取.class文件对象,通过它可以获取这个类下面的属性、构造方法、方法等信息

三种方式:

  1. package com.qfedu.test2fanshe;
  2. public class Demo2 {
  3. public static void main(String[] args) throws Exception {
  4. //有三种获取class对象的方式
  5. //1.第一种:方法名是forname 参数是字符串的包名+类名
  6. Class<?> aClass = Class.forName("com.qfedu.test2fanshe.Person");
  7. System.out.println(aClass);
  8. //2.第二种:
  9. Class<Person> personClass = Person.class;
  10. System.out.println(personClass);
  11. //3.第三种:
  12. Class<? extends Person> aClass2 = new Person().getClass();
  13. System.out.println(aClass2);
  14. }
  15. }

2.获取Constructor类对象

2.1获取构造方法的四个方法

Demo3

  1. getConstructors() 方法名 获取当前类下面的所有非私有化的构造方法对象

  2. getDeclaredConstructors() 方法名 获取当前类下面的所有构造方法对象

  3. getConstructor() 方法名 通过参数的不同,来获取所对应的非私有的构造方法

  4. getDeclaredConstructor() 方法名 这个可以获得私有的构造方法,加Declared都是可以获得私有的

  1. package com.qfedu.test2fanshe;
  2. import java.lang.reflect.Constructor;
  3. public class Demo3 {
  4. public static void main(String[] args) throws Exception {
  5. Class<?> aClass = Class.forName("com.qfedu.test2fanshe.Person");
  6. //getConstructors() 方法名
  7. //获取当前类下面的所有非私有化的构造方法对象(获取public修饰的构造方法)
  8. Constructor<?>[] constructors = aClass.getConstructors();
  9. for (Constructor<?> constructor : constructors) {
  10. System.out.println(constructor);
  11. }
  12. System.out.println("-------------------------");
  13. //获取当前类下面的所有构造方法对象
  14. //getDeclaredConstructors() 方法名
  15. Constructor<?>[] constructors1 = aClass.getDeclaredConstructors();
  16. for (Constructor<?> constructor : constructors1) {
  17. System.out.println(constructor);
  18. }
  19. System.out.println("-------------------------");
  20. //通过参数的不同,来获取所对应的非私有的构造方法
  21. //getConstructor()方法名 ()里啥也不写或者null 获取无参构造
  22. Constructor<?> constructors2 = aClass.getConstructor();
  23. System.out.println(constructors2);//无参构造
  24. Constructor<?> constructors3 = aClass.getConstructor(String.class,int.class);
  25. System.out.println(constructors3);//带有String和int的有参构造
  26. System.out.println("-------------------------");
  27. //这个可以获得私有的构造方法,加Declared都是可以获得私有的
  28. Constructor<?> constructors4 = aClass.getDeclaredConstructor(int.class);
  29. System.out.println(constructors4);
  30. }
  31. }

2.2创建对象是通过构造方法创建的

  1. //newInstance这个方法是调用Contructor对象调用的
  2. Person person = (Person)constructors2.newInstance();
  3. System.out.println(person);
  4. Person person1 = (Person)constructors3.newInstance("博儿",18);
  5. System.out.println(person1);

3.获取Method类对象

Method[] getMethods() public修饰的方法以及父类继承过来的Object下的方法

Method[] getDeclaredMethods() 获取自己下面的所有方法(不含父类),无论什么修饰的

Method getMethod(“方法名”,方法参数数据类型),获取指定public一个方法,无参的写null

Method getDeclaredMethod(“wc”, null) 获取一个方法 可以获取私有的

Object invoke(Obj obj, Obj… args);【重点】Method对象的方法

  1. package com.qfedu.test2fanshe;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Method;
  4. public class Demo4 {
  5. public static void main(String[] args) throws Exception {
  6. Class<?> aClass = Class.forName("com.qfedu.test2fanshe.Person");
  7. //public修饰的方法以及父类继承过来的Object下的方法 都打印出来
  8. //getMethods()
  9. Method[] methods = aClass.getMethods();
  10. for (Method method : methods) {
  11. System.out.println(method);
  12. }
  13. System.out.println("************************");
  14. //获取自己下面的所有方法(不含父类),无论什么修饰的
  15. //getDeclaredMethods()
  16. Method[] methods1 = aClass.getDeclaredMethods();
  17. for (Method method : methods1) {
  18. System.out.println(method);
  19. }
  20. System.out.println("************************");
  21. //获取一个方法 getMethod("方法名",方法参数数据类型),无参的写null
  22. Method method = aClass.getMethod("eat", null);
  23. System.out.println(method);
  24. Method method1 = aClass.getMethod("play", String.class);
  25. System.out.println(method1);
  26. System.out.println("************************");
  27. //Object invoke(Obj obj, Obj... args);【重点】Method对象的方法
  28. //第一个参数 这个方法在那个对象下面
  29. //第二个参数 方法的实参
  30. Constructor<?> constructor = aClass.getConstructor(null);
  31. Object obj = constructor.newInstance(null);
  32. method.invoke(obj, null);
  33. method1.invoke(obj, "游戏");
  34. }
  35. }

4.获取Field类对象【类下面的属性】

Field[] getFields() 获取所有public修饰的属性

Field[] getDeclaredFields() 获取所有的属性

Field getField(“属性名字”) 获取指定public修饰的属性

Field getDeclaredField(“属性名字”) 获取指定的属性(任何修饰符都可以)

set(Object o,Object Value)拿属性对象调用的,对属性进行赋值

  1. package com.qfedu.test2fanshe;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. //
  5. public class Demo5 {
  6. public static void main(String[] args) throws Exception {
  7. Class<?> aClass = Class.forName("com.qfedu.test2fanshe.Person");
  8. //获取类对象下的的属性reflect包下的Filed
  9. //getFields() 获取所有public修饰的属性
  10. Field[] fields = aClass.getFields();
  11. for (Field field : fields) {
  12. System.out.println(field);
  13. }
  14. System.out.println("*****************");
  15. //Field[] getDeclaredFields() 获取所有的属性
  16. Field[] fields1 = aClass.getDeclaredFields();
  17. for (Field field : fields1) {
  18. System.out.println(field);
  19. }
  20. System.out.println("*****************");
  21. //Field getField("属性名字") 获取指定public修饰的属性
  22. Field field = aClass.getField("sex");
  23. System.out.println(field);
  24. System.out.println("*****************");
  25. //getDeclaredField("属性名字") 获取指定的属性(任何修饰符都可以)
  26. Field field1 = aClass.getDeclaredField("weight");
  27. System.out.println(field1);
  28. //属性对象获取出来,可以进行赋值
  29. //set(Object o,Object Value)拿属性对象调用的,对属性进行赋值
  30. //第一个参数 属性在那个对象下面
  31. //第二个参数 属性的值
  32. Constructor<?> constructor = aClass.getConstructor(null);
  33. Person person = (Person)constructor.newInstance(null);
  34. field.set(person, '男');
  35. field1.setAccessible(true);//暴力反射
  36. field1.set(person, 80.8);//私有的不能直接赋值 加上上一行的暴力反射
  37. System.out.println(person);
  38. }
  39. }

二、单例模式

模式涉及的目的是为了让代码更加简洁,效率更低,修改起来更方便

要求程序运行过程中,只保证有且只有一个对象

问题:通过构造方法和new创建的时候,都是不同的对象

现在不能一直new。只能写一个new,然后公共不用在new

不够安全,需要加锁

  1. package com.qfedu.test3danlimoshi;
  2. //单例模式
  3. class Single{
  4. String name;
  5. //static修饰 早于对象的创建
  6. //静态方法种不能使用非静态的成员属性
  7. private static Single single = null;
  8. //私有化的构造方法的目的。为了不让在这个类外面使用new关键字
  9. private Single() {
  10. }
  11. //用方法实力对象
  12. public static Single getInstance() {
  13. //来判断single是否是第一个new的
  14. synchronized (Single.class) {
  15. if (single == null) {
  16. single = new Single();
  17. }
  18. }
  19. return single;
  20. }
  21. }
  22. //弄俩线程 验证安全问题
  23. class MyThread1 implements Runnable{
  24. @Override
  25. public void run() {
  26. Single single = Single.getInstance();
  27. System.out.println(single);
  28. }
  29. }
  30. class MyThread2 implements Runnable{
  31. @Override
  32. public void run() {
  33. Single single = Single.getInstance();
  34. System.out.println(single);
  35. }
  36. }
  37. public class Demo1 {
  38. public static void main(String[] args) {
  39. //两个内存地址一样 说明是同一个对象
  40. // Single single = Single.getInstance();
  41. // System.out.println(single);
  42. // Single single1 = Single.getInstance();
  43. // System.out.println(single1);
  44. new Thread(new MyThread1()).start();
  45. new Thread(new MyThread2()).start();
  46. }
  47. }

三、java序列化(IO流)

3.1序列化对象

目的:将对象写入到文件中

ObjectOutputStream

  1. package com.qfedu.test4xuliehua;
  2. import java.io.Serializable;
  3. //在employee实现一个Serializable接口 不然在运行时会报错
  4. public class Employee implements Serializable{
  5. String name;
  6. int age;
  7. String address;
  8. public void printInfo() {
  9. System.out.println("姓名为:" + name + ",年龄为:" + age + ",住址为:" + address);
  10. }
  11. }
  1. package com.qfedu.test4xuliehua;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectOutputStream;
  6. //序列化
  7. public class Demo1 {
  8. public static void main(String[] args) throws IOException {
  9. Employee employee = new Employee();
  10. employee.name = "朱志伟";
  11. employee.age = 24;
  12. employee.address = "地球";
  13. employee.printInfo();
  14. //将employee对象进行序列化
  15. FileOutputStream fos = new FileOutputStream(new File("E:/aaa/emp.ser"));
  16. ObjectOutputStream oos = new ObjectOutputStream(fos);
  17. oos.writeObject(employee);//在employee实现一个Serializable接口
  18. oos.close();
  19. fos.close();
  20. }
  21. }

3.2反序列化对象

目的:将文件中的数据取出来 给一个对象

  1. package com.qfedu.test4xuliehua;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.io.ObjectInputStream;
  7. import com.qfedu.test4xuliehua.Employee;
  8. //反序列化
  9. public class Demo2 {
  10. public static void main(String[] args) throws IOException, ClassNotFoundException {
  11. FileInputStream fis = new FileInputStream(new File("E:/aaa/emp.ser"));
  12. ObjectInputStream ois = new ObjectInputStream(fis);
  13. Employee employee = (Employee)ois.readObject();
  14. System.out.println(employee.name);
  15. System.out.println(employee.age);
  16. System.out.println(employee.address);
  17. employee.printInfo();
  18. ois.close();
  19. fis.close();
  20. }
  21. }

总结

序列化是将对象写进文件。反序列化是从文件读取对象

有的时候,数据比较重要,存数据库的话,爬数据丢失。因此可以将序列化到本地磁盘一次备份。使用的时候再从本地反序列化出来。

四、关于框架的知识

通过反射运行配置文件的类型

类1

  1. package com.qfedu.test5;
  2. public class Service1 {
  3. public void doService1() {
  4. System.out.println("业务方法1");
  5. }
  6. }

类2

  1. package com.qfedu.test5;
  2. public class Service2 {
  3. public void doService2() {
  4. System.out.println("业务方法2");
  5. }
  6. }

测试1

  1. package com.qfedu.test5;
  2. public class Demo1 {
  3. public static void main(String[] args) {
  4. Service1 service1 = new Service1();
  5. service1.doService1();
  6. //当需要从第一个业务方法,切换到第二个业务方法
  7. //需要重新new 重新调用
  8. Service2 service2 = new Service2();
  9. service2.doService2();
  10. }
  11. }

测试2通过反射进行改进

  1. 1.首先准备一个配置文件,暂且叫spring.txt 放在项目src路径下面,里面存的是类的名字和方名字

spring.txt

  1. class=reflection.Service1
  2. method=doService1

Demo2

  1. package com.qfedu.test5;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.lang.reflect.Constructor;
  7. import java.lang.reflect.Method;
  8. import java.util.Properties;
  9. //改进Demo1 通过反射
  10. public class Demo2 {
  11. public static void main(String[] args) throws Exception {
  12. //Spring.txt文件读取内容
  13. File file = new File("D:\\eclipse-workspace\\day413\\src\\spring.txt");
  14. //Properties 这个类可以读取配置文件中的信息封装到一个对象中
  15. Properties properties = new Properties();
  16. //将配置信息里的数据封装到Properties这个对象里
  17. properties.load(new FileInputStream(file));
  18. //获取内容 Spring.txt中 =左边是键 =右边是值
  19. String className = (String)properties.get("class");
  20. System.out.println(className);
  21. String methodName = (String)properties.get("method");
  22. System.out.println(methodName);
  23. //通过类名获取类对象
  24. Class<?> aClass = Class.forName(className);
  25. //获取方法对象
  26. Method method = aClass.getMethod(methodName, null);
  27. //获取构造器对象
  28. Constructor<?> constructor = aClass.getConstructor(null);
  29. Object object = constructor.newInstance(null);
  30. method.invoke(object, null);
  31. }
  32. }

五、通过反射越过泛型的检查

泛型是在编译期间起作用的,在编译后的.class文件是没有泛型的。本质都是Object类型的数据

  1. package com.qfedu.test6fanshefanxing;
  2. import java.lang.reflect.Method;
  3. import java.util.ArrayList;
  4. public class Demo1 {
  5. public static void main(String[] args) throws Exception {
  6. ArrayList<String> list = new ArrayList<String>();
  7. list.add("啊");
  8. list.add("吧");
  9. list.add("从");
  10. // list.add(5);//报错
  11. //通过反射越过泛型
  12. //反向获取上面ArrayList对象的Class对象,
  13. //反向在调用add方法就可以
  14. Class listClass = list.getClass();//new 对象.getClass();
  15. //获取add方法 对象 add(Object obj)
  16. Method addMethod = listClass.getMethod("add", Object.class);
  17. addMethod.invoke(list, 5);//把int数据存到String类型集合里
  18. for (Object obj : list) {
  19. System.out.println(obj);
  20. }
  21. }
  22. }