01.第一章：JUnit单元测试_JUnit概述：
	1).什么是“单元测试”：指我们程序中的代码要一部分一部分的测试。
	2).什么是"JUnit":是一个进行“单元测试”的一个第三方实现的类库。免费的，开源的。
				 它是基于“注解”的，专门用于“单元测试”的软件。
	3).一些主流的IDE开发工具内部都集成了JUnit工具包。
		
02.第一章：JUnit单元测试_JUnit的使用_@Test注解：

	1).注意事项：
		1).一个类中可以有多个方法同时标记为@Test测试方法；
		    可以单独运行，可以同时运行(按方法名升序顺序一次执行)。
		2).测试方法只能是：公有、无参、无返回值的方法。
		
04.第一章：JUnit单元测试_其它注解：
	JUnit中提供的其它注解：
	1).@Before :在@Test之前被执行；多个@Before按名称降序执行
	2).@After : 在@Test之后被执行；多个@After将名称升序执行；
	3).@BeforeClass : 用在静态方法上。在@Before执行前被执行一次，而且只执行一次。
	4).@AfterClass : 用在静态方法上。在@After执行后被执行一次，而且执行一次
	示例代码：
public class Demo {
    @BeforeClass
    public static void bc(){
        System.out.println("BeforeClass .....");
    }
    @Before
    public void b1(){
        System.out.println("b1....");
    }
    @Before
    public void b2(){
        System.out.println("b2....");
    }
    @Test
    public  void show2(){
        System.out.println("show2()....");

    }
    @Test
    public void show1(){
        System.out.println("show1().....");
    }

    @After
    public void a1(){
        System.out.println("a1.....");
    }
    @After
    public void a2(){
        System.out.println("a2.....");
    }
    @AfterClass
    public static void ac(){
        System.out.println("@AfterClass 。。。。。");
    }

}
--------------------------------------------------------------
05.第二章：反射_反射的概念及演示：
	1).编写Game2类：
public class Game2 {
    public void paoTu2(){
        System.out.println("第二个版本的跑图...");
    }
}

	2).创建配置文件：game.txt
		className = cn.itheima.demo02_反射的概念及演示.Game2
		methodName = paoTu2
	3).编程：
public static void main(String[] args) throws Exception {
    //1.读取配置文件
    Properties pro = new Properties();
    FileReader in = new FileReader("game.txt");
    pro.load(in);
    in.close();

    //2.使用反射创建Game对象，并调用paoTu方法
    Class c = Class.forName(pro.getProperty("className"));
    Object obj = c.getDeclaredConstructor().newInstance();
    Method m = c.getDeclaredMethod(pro.getProperty("methodName"));
    m.invoke(obj);
}

	什么是“反射”：在运行时，程序可以通过一个字符串的“类名”，将这个类加载到程序中，并可以获取它内部的成员信息(成员属性、成员方法、构造方法)，并且可以去调用这些成员。
06.第二章：反射_运行时class文件的加载：

	1).JVM在运行时，针对每个类，在第一次使用这个类时，都会为其创建一个Class对象，而且只创建这
	   一个。	
	2).当JVM再次使用这个类时，就不需要再去访问class文件，而是通过这个Class对象就可以操作了。
	3).什么时候会创建Class对象：
		1).当程序运行后，第一次创建此类对象时；
		2).当程序运行后，第一次访问此类的静态成员时；
		
07.第二章：反射_获取Class对象的三种方式：
public static void main(String[] args) throws Exception {
    //1.Object类的getClass()方法
    Student stu = new Student();
    Class c1 = stu.getClass();

    //2.任何数据类型都有一个静态属性：class
    Class c2 = Student.class;

    //3.使用Class类的静态方法：forName(全名限定的类名)
    Class c3 = Class.forName("cn.itheima.demo04_获取Class对象的三种方式.Student");

    System.out.println(c1 == c2);//true
    System.out.println(c1 == c3);//true

}	
注意：三种方式都是先判断Class对象是否存在，如果不存在，都会自动创建一个Class对象。

08.第二章：反射_获取构造方法并创建对象：
	1).获取构造方法的方法：
		1).public Constructor[] getDeclaredConstructors():获取所有的构造方法；
		2).public Constructor getDeclaredConstructor(Class ... param):获取某个构造方法
	2).示例代码：
public static void main(String[] args) throws Exception {
    //1.创建Class对象
    Class clazz = Class.forName(
			"cn.itheima.demo05_获取构造方法并创建对象.Student");
    //2.获取公有、无参构造方法
    Constructor con = clazz.getDeclaredConstructor();

    Object obj = con.newInstance();
    Student stu = (Student)obj;

    //3.获取私有，int和String参数的构造方法
    Constructor con2 = clazz.getDeclaredConstructor(int.class, String.class);
    con2.setAccessible(true);//暴力访问
    Object obj2 = con2.newInstance(18, "张学友");
}

09.第二章：反射_获取成员属性并赋值和取值：
	1).获取成员属性的方法：
		1).public Field[] getDeclaredFields():获取所有的成员属性；
		2).public Field getDeclaredField(String fieldName):获取某个成员属性
	2).示例代码：
public static void main(String[] args) throws Exception {
    //1.获取Class对象
    Class c = Class.forName("cn.itheima.demo06_获取成员属性并赋值和取值.Student");
    //2.获取公有的、name属性
    Field f = c.getDeclaredField("name");
    //3.获取私有的age属性
    Field f2 = c.getDeclaredField("age");

    //测试：
    Student stu1 = (Student)c.getDeclaredConstructor().newInstance();
    Student stu2 = (Student)c.getDeclaredConstructor().newInstance();

    //为第一个stu1对象的name属性赋值为：刘德华
    //为第二个stu2对象的name属性赋值为：张旭阳
    f.set(stu1, "刘德华");
    f.set(stu2, "张旭阳");

    //为第一个stu1对象的age属性赋值为：19
    //为第二个stu2对象的age属性赋值为：20
    f2.setAccessible(true);
    f2.set(stu1, 19);
    f2.set(stu2, 20);

    System.out.println(stu1);
    System.out.println(stu2);
}
10.第二章：反射_获取成员方法并调用：
	1).获取成员方法的方法：
		1).public Method[] getDeclaredMethods():获取所有的成员属性；
		2).public Method getDeclaredMethod(String methodName,Class ... params):获取某个成员属性
	2).示例代码：
public static void main(String[] args) throws Exception {
    //1.获取Class对象
    Class c = Class.forName("cn.itheima.demo07_获取成员方法并调用.Student");
    //2.获取公有无参的show1()方法
    Method m = c.getDeclaredMethod("show1");

    //创对象
    Object obj = c.getDeclaredConstructor().newInstance();
    //调用方法
    m.invoke(obj);

    //3.获取私有的，有参，有返回值的show2()
    Method m2 = c.getDeclaredMethod("show2", int.class, String.class);
    m2.setAccessible(true);
    Object r = m2.invoke(obj, 18, "张旭阳");
    System.out.println("返回值为：" + r);
}
--------------------------------------------------------------
11.第三章：注解_注解的概念及作用：
	1).“注解”是写在源码中，用于对“源码进行标记”的一种语法。
	2).它的作用：
		1).给编译器看的，告诉编译器下面的代码怎么进行语法检查、编译；
			例如：class Fu{
					public void eat(){
					}
				}
				class Zi extends Fu{
					@Override
					public void eat(String s){//编译错误
					}
				}
		2).给JVM看的，告诉JVM怎样运行下面的代码：
			例如：
				class Demo{
					@Test
					public void show(){
					}
				}
12.第三章：注解_JDK内部注解：
	@Override:给编译器看的。强制重写。
	@FunctionalInterface：给编译器看的。强制定义函数式接口；
	
13.第三章：注解_自定义注解的基本格式：
	public @interface MyAnno {
}

14.第三章：注解_元注解：
	1).元注解：也是一种注解，是已经实现好了的。它用在“定义注解时”，
		    它是对“注解”进行约束的一种“注解”。
	2).可以约束：
		1).可以约束：注解可以出现在什么位置：
			例如：
			@Target(ElementType.TYPE):可以出现在类、接口上；
			@Target(ElementType.FIELD):可以出现在成员属性上；
			@Target(ElementType.CONSTRUCTOR):可以出现在构造方法上；
			@Target(ElementType.METHOD):可以出现在方法上；
			@Target(ElementType.PARAMETER):可以出现在方法形参上；
			@Target(ElementType.LOCAL_VARIABLE):可以出现在局部变量上
		2).约束：注解的声明周期；
			例如：
			@Retention(RetentionPolicy.SOURCE):注解只能出现的源码中。
			@Retention(RetentionPolicy.CLASS):注解可以出现在源码、class文件中
			@Retention(RetentionPolicy.RUNTIME):注解可以出现源码、class 、运行时
	3).示例代码：
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnno {

}
15.第三章：注解_解析注解：
	//模拟注解解析器：
public static void main(String[] args) throws Exception {
    //1.获取使用了注解的类的Class对象
    Class c = Demo.class;
    Object obj = c.getDeclaredConstructor().newInstance();
    //2.获取此类中所有的方法
    Method[] methodArray = c.getDeclaredMethods();
    //3.遍历这些方法
    for (Method m : methodArray) {
        //4.判断m是否被使用了MyAnno注解
        if (m.isAnnotationPresent(MyAnno.class)) {
            //5.执行这个方法
            m.invoke(obj);
        }
    }
}
16.第三章：注解_定义有属性的注解：
	1).定义注解：
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
    //属性格式：数据类型 变量名() [deafult 值];
    String version();//数据类型：1).所有基本类型;2).String，Class，枚举，注解；3).以上任一类型的数组
    String[] arr();
    String startsWith() default "test";
}

	2).使用和解析：
public class Demo {
    @MyAnno(version = "1.0",arr = {"aaa","bbb"},startsWith = "test")
    public void show1(){
        System.out.println("show1....");
    }

    @MyAnno(version = "2.0", arr = {"xxx", "yyy"})
    public void show2() {
        System.out.println("show2....");
    }
    @Test
    public void show3(){
        System.out.println("show3....");
    }
    //模拟注解解析器：
    public static void main(String[] args) throws Exception {
        //1.获取使用了注解的类的Class对象
        Class c = Demo.class;
        Object obj = c.getDeclaredConstructor().newInstance();
        //2.获取此类中所有的方法
        Method[] methodArray = c.getDeclaredMethods();
        //3.遍历这些方法
        for (Method m : methodArray) {
            //4.判断m是否被使用了MyAnno注解
            if (m.isAnnotationPresent(MyAnno.class)) {
                //--解析属性---//
                //获取这个注解对象
                MyAnno myAnno = m.getAnnotation(MyAnno.class);
                String v1 = myAnno.version();
                String[] arr = myAnno.arr();
                String v3 = myAnno.startsWith();
                System.out.println("version = " + v1 + 
						" arr = " + Arrays.toString(arr) + 
						" startsWith = " + v3);

                if(!m.getName().startsWith(v3)){
                    System.out.println("注意：方法应该以：" + v3 + 
					" 开头，我如果是编译器会出现编译错误，但可惜现在我不是！");
                }
                //5.执行这个方法
                m.invoke(obj);
            }
        }
    }
}
=================================================================
学习目标总结：
1 . 能够使用Junit进行单元测试
	@Test
	public void show1(){
	}
2. 能够通过反射技术获取Class字节码对象
	1).对象.getClass()
	2).类名.class
	3).Class.forName(全名限定的类名)
3. 能够通过反射技术获取构造方法对象， 并创建对象。
	Class c = Class.forName(...);
	Constructor con = c.getDeclaredConstructor(形参数据类型.class ...);
	Object obj = con.newInstance();
	Student stu = (Student)obj;
	...
4. 能够通过反射获取成员方法对象， 并且调用方法。
	Class c = Class.forName(...);
	Method m = c.getDeclaredMethod(方法名,形参数据类型class....);
	Object obj = c.getDeclaredConstructor().newInstance();
	返回值 = m.invoke(obj,实参...);
5. 能够说出注解的作用
	1).注解就是在源码中的一个“标记”，用于通知编译器/JVM（解析器）怎样编译/执行下面的代码。
6. 能够自定义注解和使用注解
	1).定义自定义注解：
		@Target(ElementType.METHOD)
		@Retention(RetensionPolicy.RUNTIME)
		public @interface MyAnno{
		}
7. 能够说出常用的元注解及其作用
		@Target(ElementType.METHOD):限定注解可以出现的位置。
		@Retention(RetensionPolicy.RUNTIME)：限定注解的生命周期。

8. 能够解析注解并获取注解中的数据
	参考demo09
9. 能够完成注解的MyTest案例
	参考demo09