反射:
反射:解剖一个类(变量(Field)、方法(Method)、构造方法(Constructor))。
Java反射:在程序运行的过程中,可以对任意一个类型进行任意的操作,例如:加载任意类型,调用类型的任意方法,获取任意的成员变量、构造方法,可以创建该类的对象。
如果要获取一个类型的各种内容,首先要获得这个类的字节码对象。
解剖这个类,获取成员,需要使用Class类型。
这种动态的获取信息以及动态访问成员的这种方式,称为反射。
获取类的字节码对象(Class类型的对象)的三种方式:
对象名.getClass():返回某个引用指向的具体对象所属的运行类的字节对象。获取到的是那个真正用于创建对象的字节码对象。
类名.class:如果已经有类名,可以通过类名.class的方式来获取这个类的字节码对象。
通过Class.forName(类的全路径):Class中的一个静态方法,可以根据传一个类的全类名,动态地加载某个类型,可以获取该类的字节码对象,扩展性强。
解剖成员变量
Field | getField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。 | ||
Field[] | 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。 | ||
Field | getDeclaredField(String name) 返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。 暴力反射 | ||
Field[] | 返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。 |
void | set(Object obj, Object value) 将指定对象参数上的此 Field对象表示的字段设置为指定的新值。 |
解剖构造方法
Constructor<T> | getConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。 | ||
Constructor<?>[] | 返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 类对象。 | ||
Constructor<T> | getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。 | ||
Constructor<?>[] | 返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组 类 。 |
T | newInstance(Object... initargs) 使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。 |
解剖成员方法
方法 | getMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。 |
方法[] | 返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。 |
Object | invoke(Object obj, Object... args) 在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。 |
实例一:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test01 {
public static void main(String[] args) throws Exception {
/* //在文档里面,查找类的时候直接输入 类,输入Class找不到
Class class1 = Person.class;//获取类的字节码对象的第一种方式 类名.class
Class class2 = new Person().getClass();//获取类的字节码对象的第二种方式 对象名.getClass()
Class class3 = Class.forName("com.xiongluoluo.review.Person");
获取类的字节码对象的第三种方式,使用Class中的静态方法forName,
输入类的全路径,获取类的字节码对象,此方法需要声明异常,但是很常用
Class.forName("全路径")方法获得的类型默认是Class
System.out.println(class1==class2);//true
System.out.println(class2==class3);//true
//类的字节码文件只会加载一次,存在方法区,所以,都是一样的
System.out.println("***************************");
//使用类的字节码对象,访问类的成员变量
//Field field1 = class1.getField("name");//普通反射:只能访问public
//由于name字段是私有的,所以这样写会抛出异常
Field field2 = class2.getDeclaredField("name");//暴力反射:可以访问类中所有成员变量
System.out.println(field2);
Field[] fields1 = class1.getFields();//普通反射:只能访问类中所有被public修饰的成员变量
Field[] fields2 = class2.getDeclaredFields();//暴力反射:能访问类中所有成员变量,无论是私有还是非私有的
for(Field field : fields1) {
System.out.println(field);
}
System.out.println("***************************");
for(Field field : fields2) {
System.out.println(field);
}
System.out.println("***************************");
//使用类的字节码对象,访问类的构造方法
Constructor c1 = class1.getConstructor();//获取无参的构造方法(public修饰的),如果无参构造方法不是public修饰,将会抛出异常
System.out.println(c1);
Constructor c2 = class1.getDeclaredConstructor(String.class,int.class,boolean.class);
//获取有参数的构造方法时,参数要写参数类型的的字节码对象.(获取有参的构造方法,无论构造方法是私有还是非私有,都可以获取)
System.out.println(c2);
System.out.println("***************************");
Constructor[] cons = class1.getConstructors();//获取所有的public修饰的构造方法
for(Constructor c : cons) {
System.out.println(c);
}
System.out.println("***************************");
Constructor[] cons2 = class2.getDeclaredConstructors();//获取所有构造方法
for(Constructor c : cons2) {
System.out.println(c);
}
System.out.println("***************************");
//使用类的字节码对象,访问类的成员方法
Method method1 = class1.getMethod("getName");
Object invoke = method1.invoke(new Person());
System.out.println(invoke);
Method method2 = class2.getDeclaredMethod("setAge", int.class);
System.out.println(method2.invoke(new Person(), 22));
Method[] methods1 = class1.getMethods();//与上面的机制有所不同,这个可以获取所有的方法,包括父类
for(Method m : methods1) {
System.out.println(m);
}
System.out.println("***************************");
Method[] methods2 = class2.getDeclaredMethods();//这个只能获取子类中特有的方法
for(Method m : methods2) {
System.out.println(m);
}*/
Class class1 = Class.forName("com.xiongluoluo.review.Person");
Person p = (Person)class1.getConstructor().newInstance();
//Constructor con = class1.getConstructor(String.class,int.class,boolean.class);只能访问公有构造方法
Constructor con1 = class1.getDeclaredConstructor(String.class,int.class,boolean.class);
System.out.println(con1);
con1.setAccessible(true);//如果构造方法是私有的,新建实例前需要设置访问权限,不然会抛异常
Person p2 = (Person)con1.newInstance("熊落落",22,true);
System.out.println(p2);
}
}
class Person{
private String name;
private int age;
private boolean sex;
public Person() {
super();
// TODO Auto-generated constructor stub
}
private Person(String name, int age, boolean sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
private Person(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
public void run() {
System.out.println("我在跑步ing");
}
public void sleep() {
System.out.println("我在睡觉");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
实例二:
import java.util.Scanner;
//输入Apple,流出苹果汁;输入Orange,流出橘子汁(用反射做)
public class Test02 {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入Apple或者Orange:");
String value = sc.nextLine();
Class c = Class.forName("com.xiongluoluo.review." + value);
Fruit f = (Fruit)c.newInstance();
f.blow();
}
}
interface Fruit{
public void blow();
}
class Apple implements Fruit{
public void blow() {
System.out.println("流出苹果汁");
}
}
class Orange implements Fruit{
public void blow() {
System.out.println("流出橘子汁");
}
}
实例三:
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
public class Test03 {
public static void main(String[] args) throws Exception {
Class c = Class.forName("com.xiongluoluo.review.Computer");
Computer com = (Computer)c.newInstance();
com.start();
Properties p = new Properties();
InputStream is = new FileInputStream("config.properties");
p.load(is);
Enumeration<Object> elements = p.elements();
while(elements.hasMoreElements()) {
String element = (String)elements.nextElement();
Class c1 = Class.forName("com.xiongluoluo.review." + element);
Card card = (Card)c1.newInstance();
com.useCard(card);
}
com.close();
}
}
单元测试:
测试分类:黑盒测试、白盒测试
单元测试、集成测试
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class Test04 {
//不能单独执行
@Before
public void before() {
System.out.println("测试方法执行前执行");
}
//放在主类中,主方法外
//选中方法名,点击右键Run As执行测试方法
@Test
public void run() {
int a = 1;
int b = 3;
System.out.println(a+b);
}
//不能单独执行
@After
public void after() {
System.out.println("测试方法执行后执行");
}
}
Jar包:
- 如何生成jar包
右键项目-->export-->java-->jar file-->选择文件夹(命名.jar)
- 如何使用jar包
新建lib文件夹,把jar包复制进去,需要build path,就可以使用
- 第三方jar包
Github
Scanner:
Scanner:是一个扫描器,可以扫描指定设备的基本数据类型和字符串。
构造方法:
Scanner(File source)
构造一个新的 Scanner ,产生从指定文件扫描的值。
Scanner(String source)
构造一个新的 Scanner ,产生从指定字符串扫描的值。
Scanner(InputStream source)
构造一个新的 Scanner ,产生从指定输入流扫描的值。
常用方法
nextXxx:获取基本数据类型 分隔格:空格 换行
没有nextChar(),nextString()这两个方法
nextLine():获取字符串 分隔符:换行
next():获取字符串 分隔符:空格
空格分隔符和换行分隔符交叉使用
import java.util.Scanner;
import com.ujiuye.bean.Student;
public class Demo03 {
public static void main(String[] args) {
//method01();
//method02_第一种解决方案();
//method02_第二种解决方案();
method02_第三种解决方案();
Student s = new Student();
}
private static void method02_第三种解决方案() {
//都转为字符串,数字通过Integer.parseInt(str)获取
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
int i = Integer.parseInt(line);
String str = sc.nextLine();
System.out.println(i);
System.out.println(str);
}
private static void method02_第二种解决方案() {
//定义两个Scanner,上下无联系
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
System.out.println(i);
sc = new Scanner(System.in);
String str = sc.nextLine();
System.out.println(str);
}
private static void method02_第一种解决方案() {
Scanner sc = new Scanner(System.in);
//空格 换行 10
int i = sc.nextInt();
System.out.println(i);
sc.nextLine();//返回来的第一个空串,但是不接收这个数据
//回车
String str = sc.nextLine();
System.out.println(str+"...");
}
private static void method01() {
Scanner sc = new Scanner(System.in);
//空格 换行 10
int i = sc.nextInt();
System.out.println(i);
//回车
String str = sc.nextLine();
System.out.println(str+"...");
}
}
建议:不要交叉使用。(我一定不会用的,麻烦)