Day23-反射

总结

我是最棒的!基础不牢,地动山摇!

JUnit4单元测试

测试类命名

测试类+Test

测试方法命名

test+测试方法名,修饰符为public,返回值类型为void.在方法上面加上@Test注解,运行时Run as JUnit4

其他

@Before 每次测试一个功能都会先执行

@After 每次测试一个功能都会最后执行

jar包的导入和导出

导入

在根目录下创建一个lib文件夹,然后将jar包拖入lib中,再右键点击jar包add to build path

红色感叹号代表可能包出错,解决方案是全部删除再重新导入

导出

使用eclipse带的export导出jar文件

资源文件解析

配置文件

配置文件一般用来解决硬编码问题(写死的代码),主要有xml,properties等

一般先在根目录下创建配置文件的source文件夹

传统方式读取配置文件

使用Properties类,new的方式创建流对象,可能因为路径问题导致读取不到配置文件,所以我们现在基本不用

package cn.itsource.configuration;

import java.io.FileReader;
import java.util.Properties;

public class PropertiesTest {

	public static void main(String[] args) {
		Properties p = new Properties();
		try(
				FileReader fr = new FileReader("mysql.properties");
				){
			p.load(fr);
			
			System.out.println(p.getProperty("username"));
			System.out.println(p.getProperty("password"));
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

}

//控制台打印报错信息,因为路径没有写完
/*
	java.io.FileNotFoundException: mysql.properties (系统找不到指定的文件。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at java.io.FileReader.<init>(FileReader.java:58)
	at cn.itsource.configuration.PropertiesTest.main
	(PropertiesTest.java:11)
*/
try(
		FileReader fr = new FileReader("db/mysql.properties");
		)
//将路径改成db/mysql.properties就可以读取配置文件中的信息
//控制台打印
//root 
//root

改进的三种方式

  1. 通过当前类的字节码文件的方式

    这种方式需要在路径前面加一个/

    //核心代码
    PropertiesTest2.class.getResourceAsStream("/mysql.properties");
    

    完整代码

    package cn.itsource.configuration;
    
    import java.io.InputStream;
    import java.util.Properties;
    
    public class PropertiesTest2 {
    
    	public static void main(String[] args) {
    		Properties p = new Properties();
    		try{
    			InputStream is = PropertiesTest2.class.getResourceAsStream("/mysql.properties");
    			p.load(is);
    			
    			System.out.println(p.getProperty("username"));
    			System.out.println(p.getProperty("password"));
    		}catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    
    
  2. 通过当前类的加载器的方式

    这种方式直接写上路径即可

    //核心代码
    PropertiesTest4.class.getClassLoader().getResourceAsStream("mysql.properties");
    

    完整代码

    package cn.itsource.configuration;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    /**
     * 通过字节码对象的类加载器读取配置文件
     */
    public class PropertiesTest3 {
    
    	public static void main(String[] args) {
    		Properties p = new Properties();
    		InputStream is = null;
    		try{
    			is = PropertiesTest4.class.getClassLoader().getResourceAsStream("mysql.properties");
    			p.load(is);
    			
    			System.out.println(p.getProperty("username"));
    			System.out.println(p.getProperty("password"));
    		}catch (Exception e) {
    			e.printStackTrace();
    		}finally {
    			try {
    				if(is != null){
    					is.close();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    }
    
    
    
  3. 通过当前线程类的加载器方式

    这种方式写上路径即可

    //核心代码,获取当前线程类的加载器
    Thread.currentThread().getContextClassLoader().getResourceAsStream("mysql.properties");
    

    完整代码

    package cn.itsource.configuration;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    /**
     * 通过字节码对象的类加载器读取配置文件
     */
    public class PropertiesTest4 {
    
    	public static void main(String[] args) {
    		Properties p = new Properties();
    		InputStream is = null;
    		try{
    			is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mysql.properties");
    			p.load(is);
    			
    			System.out.println(p.getProperty("username"));
    			System.out.println(p.getProperty("password"));
    		}catch (Exception e) {
    			e.printStackTrace();
    		}finally {
    			try {
    				if(is != null){
    					is.close();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    }
    
    

设计模式

单例模式

常用来做一些初始化工作,比如日志文件等

  • 饿汉模式
package cn.itsource.designpattern;
/**
 *	用单例模式一般都用饿汉模式,线程安全并且获取对象效率高
 *	可以使用静态代码块的方式来对它进行优化 ,让它不会一直占用空间
 */
public class Singleton {
	
	public static final int a = 5;
	private static final Singleton INSTANCE;
	
	private Singleton(){
		
	}
	
	static{
		System.out.println("666");
		INSTANCE = new Singleton();
	}
	
	public static Singleton getInstance(){
		return INSTANCE;
	}
}

  • 懒汉模式
package cn.itsource.designpattern;

public class SingletonLazy {

	private static SingletonLazy instance;
	
	/**
	 * 私有化构造方法
	 */
	private SingletonLazy(){
		
	}
	
	/**
	 * 双重校验锁解决懒汉模式线程安全问题
	 * @return
	 */
	public static SingletonLazy getInstance(){
		if(instance == null){
			synchronized (SingletonLazy.class) {
				if(instance == null){
					instance = new SingletonLazy();
				}
			}
			
		}
		return instance;
	}
	
}

装饰者模式

在不改变原有功能的基础上,写一个子类继承他,并且加强它的原有功能

简单工厂模式

优点:创建对象和使用对象的功能分离

缺点:扩展性弱,如果添加了新产品,则需要修改工厂方法

适用于产品较少并且不经常变动

适配器模式

解决了两个功能的协同工作

扩展性强

ThreadLocal

解决线程安全问题

package cn.itsource.threadlocal;

public class ThreadLocalTest {
	static Integer a = 1;//有线程安全的代码
	public static void main(String[] args) {
		
//		new Thread(new Runnable() {
//			@Override
//			public void run() {
//				//创建一个ThreadLocal对象,将有线程安全的变量类型传入
//				ThreadLocal<Integer> local = new ThreadLocal<Integer>();
//				a = 66;
//				//将有线程安全的变量保存到ThreadLocal对象
//				local.set(a);
//				while (true) {
//					try {
//						Thread.sleep(200);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//					//取出ThreadLocal对象中保存的变量
//					System.out.println("新线程:"+local.get());
//				}
//			}
//		}).start();
		
		new Thread(() -> {
			//创建一个ThreadLocal对象,将有线程安全的变量类型传入
			ThreadLocal<Integer> local = new ThreadLocal<Integer>();
			a = 66;
			//将有线程安全的变量保存到ThreadLocal对象
			local.set(a);
			while (true) {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//取出ThreadLocal对象中保存的变量
				System.out.println("新线程:"+local.get());
			}
		}).start();
		
		
		ThreadLocal<Integer> local = new ThreadLocal<Integer>();
		a = 99;
		local.set(a);
		while (true) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("main线程=====>:"+local.get());
		}
	}
}

反射

通过一个全限定类名,动态的获取该类的字节码文件

优点:

  1. 提高开发灵活度,提高程序的扩展性
  2. 框架(提高开发效率的别人封装好的代码)底层都是使用反射技术

缺点:

​ 破坏封装性,性能低下(如果以后,可以不用反射技术,就不用)

反射中常用的方法

//获取字节码文件
Class clazz = Class.forName(全限定类名);

通过字节码文件获取构造方法

/*
Constructor[] constructors = clazz.getConstructors() 获取public修饰的构造方法数组
Constructor[] constructors = clazz.getDeclaredConstructors() 获取所有造方法数组
Constructor constructor = clazz.getConstructor(Class 参数字节码)根据参数类型获取指定的的构造方法
*/
//通过构造方法对象去用构造方法创建对象 => 相当于new 一个对象
	Object instance  = constructor.newInstance(Object 实参);

通过字节码文件获取普通方法

/*
Method[] methods = clazz.getMethods() 获取public修饰的普通方法数组
Method[] methods = clazz.getDeclaredMethods() 获取所有普通方法数组
Method method = clazz.getMethod(String methodName,Class... 参数字节码)根据方法名和参数类型获取指定的的方法,如果方法没有形参,则Class可变参数不用写
*/

//调用方法若为静态,则对象为null。不为静态,对象就是用构造方法创建的。实参根据调用的方法本身来定
method.invoke(Object 对象,实参);

通过字节码文件获取字段

/*
Field[] fields = clazz.getFields() 获取public修饰的字段数组
Field[] fields = clazz.getDeclaredFields() 获取所有权限的字段数组
Field field = clazz.getDeclearField(String fieldName) 根据字段名获取指定字段
Field field = clazz.getField(String fieldName)根据字段名获取指定public修饰字段
*/

//如果字段是private修饰,那么我们可以通过破坏封装性来改变它的字段值
	field.setAccessible(true);

//通过当前的字段对象,给某一个字段赋值取值
	field.get(Object obj);
	field.set(Object obj, Object value);


猜你喜欢

转载自blog.csdn.net/t384061961/article/details/100181567