首页 > 其他 > 详细

Day07 jdk5.0新特性&Junit&反射

时间:2016-07-29 22:43:56      阅读:225      评论:0      收藏:0      [点我收藏+]

day07总结

今日内容

  • MyEclipse安装与使用
  • JUnit使用
  • 泛型
  • 1.5新特性
    • 自动装箱拆箱
    • 增强for
    • 静态导入
    • 可变参数方法
  • 枚举
  • 反射

MyEclipse安装与使用(yes)

安装MyEclipse

先安装了JDK

?

MyEclipse介绍

?

  • MyEclipse是Eclipse的一个插件;
  • MyEclipse是需要花钱的;
  • MyEclipse官网不在欢迎中国人登录;

?

MyEclipse使用

?

1 创建项目
  • 选择工作空间;
  • 工作空间路径不能有空格和中文;
  • 工作空间以班名来命名:20130922
  • 创建项目;项目名以day0x为前缀,例如今天是第1天,那么今天的项目以day01为前缀;
  • 创建项目时配置JRE,如果不配置就是使用默认JRE;
  • 其实我们指定的都是JDK,而不是JRE。因为我们要开发Java项目,而不是运行!
  • 创建类,注意,所有类都必须有包,所有类名、变量名、方法名等一定要按规范来做;
  • 默认包名以cn.itcast为前缀;
  • 指定类的修饰符;
  • 指定类的父类;
  • 指定类的接口;
  • 指定方法:是否创建main、是否通过父类创建构造器、是否实现抽象方法;
  • 编写Hello World;
  • 运行java程序的方式;

?

断点调试模式运行java程序

?

1 断点调试的目的
  • 跟踪源代码;
  • 观察程序运行状态;

?

2 调试程序1

  编写求和代码

  • 设置断点;
  • debug运行;
  • 进入debug透视图;
  • 程序会运行到断点处停住;
  • 当前行还没有运行;
  • 查看变量值:选中变量à鼠标右键àWatch;
  • F5(跳入)、F6(跳过)、F7(跳出);

?

3 调试程序2

使用Arrays.binarySearch()编写折半搜索数组元素代码

  • 设置断点;
  • 测试跳入;
  • 测试跳过;
  • 测试跳出;
  • 添加断点;
  • 测试进入下一断点;
  • 测试返回当前方法栈的头部(Drop To Frame);
  • 清除断点;
  • 清除表达式;
  • 注意,停止程序!

?

MyEclipse快捷键

?

  1. MyEclipse常用快捷键1
  • Alt + /(内容助理):补全;
  • Ctrl + 1(快速定位):出错时定位错误,与点击"红X"效果一样;
  • Ctrl + Shift + O:导包;
  • Ctrl + Shift + F:格式化代码块;

?

2 MyEclipse常用快捷键2
  • Ctrl + Shift + T:查看源代码;
  • Ctrl + 点击源代码:查看源代码;
  • F3:查看选中类的源代码;
  • Alt + 左键:查看源代码时的"原路返回";
  • Ctrl + Shift + X:把小写修改为大写;
  • Ctrl + Shift + Y:把小写修改为小写;
  • Ctrl + Alt + 下键:复制当前行;
  • Ctrl + /:添加或撤销行注释;
  • Ctrl + Shift + /:对选中代码添加段注释;
  • Ctrl + Shift + \:撤销当前段注释;
  • Alt + 上键:向上移动当前行;
  • Alt + 下键:向上移动当前行;
  • Ctrl + D:删除当前行;

?

MyEclipse:

  • 工作空间;
  • 项目名称;
  • 包名;
  • 类名;
  • Alt + /、Ctrl + 1、Ctrl + shift + o、Ctrl + shift + f

?

JUnit使用

测试1

?

1 JUnit的作用

JUnit用来为程序写测试用例。

以前总是需要自己写个main方法来测试某个方法。当需要测试另一个方法时,还要在main中再写一段代码对另一个方法进行测试。

JUnit是专业的测试工具!!!

?

2 为测试程序创建包

  为JUnit写一个包:junit.test包。所有测试类都写到这个包中。

?

3 编写Person类

package cn.itcast;

?

public class Person {

????public void run() {

????????System.out.println("run");

????}

????

????public void eat() {

????????System.out.println("eat");

????}

}

?

4 编写Person的测试用例类:PersonTest

包资源管理器à选中Person类à右键ànewàJUnit TestCaseà修改包名为junit.testà下一步à选中要测试的方法。

每个测试方法都会有@Test注解。

在生成的PersonTest中给testXXX()方法添加测试内容。

?

5 运行测试用例
  • 选中PersonTest类à右键àRun asàJUnit Test;
  • Outlineà选中testXXX()方法à右键àRun as à JUnit Test。

?

测试2

?

1 setUp()和tearDown()
  • 再创建一个测试用例;
  • 勾选setUp()和tearDown()方法;
  • setUp()方法会有@Before注解;
  • tearDown()方法会有@After注解。
  • setUp()方法会在所有测试方法之前运行;
  • setUp()方法可以用来为每个测试方法在测试之前做一些准备工作;
  • tearDown()方法会在所有测试方法之后运行。
  • tearDown()方法可以用来为每个测试方法在测试之后做一些清理工作;

?

测试3

?

1 setUpBeforeClass()和tearDownAfterClass()
  • 再创建一个测试用例;
  • 勾选setUpBeforeClass()和tearDownAfterClass();
  • setUpBeforeClass()方法会有@BeforeClass注解;
  • tearDownAfterClass()方法会有@AfterClass注解;
  • setUpBeforeClass()方法会在测试开始之前被调用;
  • setUpBeforeClass()方法可以用来在测试开始之前做一些准备工作;
  • tearDownAfterClass()方法在测试结束之后被调用;
  • tearDownAfterClass()方法可以用来在测试结束之后做一些清理工作;
  • 这两个方法用的没有setUp()和tearDown()多。

?

@Test – 必须是public的、返回为void、无参的方法

@Before --必须是public的、返回为void、无参的方法

@After --必须是public的、返回为void、无参的方法

@BeforeClass – 必须是public的、static的、返回为void、无参的方法

@AfterClass – 必须是public的、static的、返回为void、无参的方法

?

泛型

泛型概述

?

1 数组与集合

  Java中可以定义任意类型的属性,例如String[]中存放的就是String类型的数据,我们称之为持有String类型的数组。但1.5之前时,Java的集合类却只能持有Object类型,1.5时添加了泛型的概念,泛型允许Java创建持有任意类型的集合对象,例如:new ArrayList<String>()表示这个ArrayList中只能持有String类型的对象。

?

2 类型变量(参数)

具有一个或多个类型参数的类就是泛型类。

泛型类都至少有一个类型变量,你需要在创建泛型类对象时给类型变量赋值。当然,你要给类型变量赋的值必须是一个类型!

ArrayList<String> arr = new ArrayList<String>();

其中String就是给ArrayList类的类型变量赋值。在ArrayList类中所有使用类型变量的地方都会被String所替换。例如:boolean add(E e),其中e的类型就是变量,它会被String替换,最终变成boolean add(String e)。E get(int index)方法中返回值的类型为变量,它也会被String替换,最终变成String get(int index)。

?

3 泛型的好处

将运行期遇到的问题转移到了编译期。例如在1.4时,ArrayList类的add()方法参数还是Object类型,当然get()方法的返回值类型也是Object。这就说明使用get()方法获返回值后,你还需要强转。错误的强转可能会出现ClassCastException。

ArrayList list = new ArrayList();

list.add("hello");

Integer i = (Integer)list.get(0);//抛出异常

?

这个问题在有了泛型之后就不会再有了。

ArrayList<Integer> list = new ArrayList<Integer>();

list.add("hello");//编译出错!

Integer i = (Integer)list.get(0);

?

  很明显,是泛型把只能在运行时才能找到的错误推向了编译期!这就是泛型的优点!!!

?

定义泛型类(接口)

?

1 自定义泛型类的语法

自定义泛型类的语法基本与定义正常的法一样:

public class A<T> {}

定义泛型类时,需要在类名后面给出一对尖括号,在尖括号中给出1~N个类型变量。

?

2 泛型类中使用类型变量

用户在使用泛型类时,需要为类型变量赋值。例如:new A<String>()。

在泛型类中可以使用类型变量:

public class A<T> {

private T t;

public A(T t) {

this.t = t;

}

public T get() {

return t;

}

}

当用户创建A类对象时,就会给A类的类型变量T赋值,例如:new A<String>(),这说明在A类中所有的T都会被String替换。

public class A {

private String t;

public A(String t) {

this.t = t;

}

public String get() {

return t;

}

}

?

3 类型变量的限制

上例中,A类中定义了T类型的属性t,这个属性t的类型是一个变量,无法确定的,因为你在定义A类时,根本就不知道用户会传递什么类型给T,所以你也不能调用属性t的方法,因为你不知道t的类型,就不知道它有什么方法。但是,我们知道任何类都是Object类的子类,那么就说明你可以调用属性t的Object中存在的方法。

注意,你不能使用T类型的构造器:new T(),因为你不能确定t的类型,那么也就不知道它有什么样的构造器,甚至是否有public构造器,所以不能创建。

相同的道理,也不能创建T类型的属性,例如:new T[10],这也是不行的!

还有一点,在泛型类中,static方法中不能使用类型变量T。

?

继承(实现)泛型类(接口)

?

1 继承泛型类之一

如果当前类是泛型类,那么在继承(实现)泛型类(接口)时,可以把自己的类型变量传递给父类(接口)。

public class ArrayList<E> implements List<E> {

}

可以这样来理解,其中public class ArrayList<E>中的<E>表示定义了一个泛型类,其中E是定义的类型变量,而implements List<E>中的<E>表示给List接口传递<E>,这是在使用变量类型E,而不是在定义了。

ArrayList<String> arr = new ArrayList<String>();

在用户创建ArrayList类对象时,传递给ArrayList类中的E的值是String,那么ArrayList会把这个String再传递给List中的E。

你可能会想,为什么一定要给父类或接口传递类型变量。那我会问你,实现类不给List接口中的E来赋值,谁来给它赋值?难道你想new List<String>()这样赋值么?接口是不能被实例化的,你只能让实现类来赋值,你不赋值,接口中的get()方法一直返回E类型!!!

?

2 继承泛型类之二

泛型类的子类不一定必须为泛型类,也可以是非泛型类。这时因为子类没有类型变量可以传递给父类,那么也就能传递给父类类型常量了。

public class String implements Comparable<String> {

public int compareTo(String other) {…}

}

?

  这时,在重写父类中方法时,所有的类型变量都是String了。

?

泛型方法

?

1 泛型方法定义

泛型类是说明这个类有类型变量,在创建这个类对象时需要给类型变量赋值。泛型方法是说明这个方法有类型变量,在调用这个方法时需要给类型变量赋值。

public <T> T get(T[] ts, int index) {

return ts[index];

}

注意,在返回值前面定义类型变量。

get()方法是一个泛型方法,它有一个类型变量T,这说明在调用get()方法时需要给get()方法的T赋值。

如果要定义一个有意义的泛型方法,那么:

所以,通常在调用泛型方法时,只需要传递参数就可以了,例如:

String[] strs = …

String s = o.get(strs, 0);

上面代码中给get()方法的类型变量T赋值为String,因为传递的参数为String数组,所以就是给T赋值为String。

当然,也可以显示给出类型变量的值:o.<String>get(strs,0),在点后面,方法名前面给出类型值,但一般人不会这么打代码。

?

泛型的边界

编译期状态:编译期状态,例如内部类!内部类就是只有编译器知道,而JVM不知道什么叫内部类!

1 泛型的擦除

泛型其实是编译期状态,即JVM不知道什么是泛型,在JVM那里所有类都是正常的类。没有类型变量。一切的一切都是编译器干的好事儿!

其实List的get()方法返回值还是Object,只是编译器帮我们添加了强转的语句。但这个强转一定不会出现问题。因为本来add()方法添加元素已经限制过了,那么在get()时,一定不会出现强转的问题。

也就是说,在ArrayList类中持有的还是Object类型,而不是我们指定的类型。当然,就算是JVM没有泛型,但编译器会帮我们完成这些问题,我们就可以当泛型真的存在。

?

2 泛型边界限定的类型值的范围

通常我们看到的泛型类都没有边界限定,也就是说可以给泛型类的类型变量赋任意类型的值(当然基本类型是不可以的)。

java允许给类型变量指定边界,这样用户在给类型变量赋值时就必须在边界之内。

public class A<T extends Number> {}表示用户可以给T赋值为Number或Number的子类型。例如:new A<Integer>()这是可以的,但new A<String>()是不可以的。

?

通配符

?

1 通配符的作用

Object[] objs = new String[10];

objs[0] = new Integer(100);

上面代码编译是可以通过的,但在运行时会出现ArrayStoreException。因为objs数组真实的身份是String[],向String[]数组中存放Integer对象当然是不行的。

ArrayList<Object> list = new ArrayList<String>();

list.add(new Integer(100);

上面代码在第一行位置编译失败,因为泛型根本就不让把ArrayList<String>赋值给ArrayList<Object>,对于ArrayList<Object>而言,只能赋值ArrayList<Object>,其他的什么都不能赋值。

这也说明一个问题:

public static void printList(List<Object> list) {…}

调用printList()方法只能传递给它List<Object>类型的参数,而不能传递List<String>,或者List<Integer>,这说明我们的printList()方法有很多的限制,不够通用!!!你可能会想我再重载几次printList()方法吧,但这是行不通的!

public static void printList(List<Object> list) {…}

public static void printList(List<String> list) {…}

因为JVM不知道什么是泛型,这两个方法在到了JVM那里时都是会把泛型参数擦除,这两个方法就是相同的方法了,擦除之后即:

public static void printList(List list) {…}

public static void printList(List list) {…}

当然JVM不可能看到这样的代码,因为编译器不能让你编译通过!

处理这个问题需要使用通配符!

?

2 子类型通配符

public static void printList(List<? extends Person> list) {…}

这回可以传递给printList()方法List<Student>,以及List<Teacher>参数了。只要类型参数为Person,或者是Person子类型就都可以。

你可以这样来理解通配符,通配符表示"不知道"的意思。即一个问号!但子类型通配符还是知道一些信息的,它只知道用户转递的类型参数一定是Person的子类型。虽然使用了通配符之后printList()方法更加通用了,但是这也是要付出一些代价的。因为不知道List中类型参数的真实类型,所以就不能调用list的add()方法了。你可能会想add(new Student())应该是可以的,但如果List是List<Teacher>呢,你怎么向这样的List添加Student呢?再想一想,add()方法已经作废了,什么都传递不了。

?

3 父类型通配符

public static void printList(List<? super Student> list) {…}

可以传递给printList()方法List<Student>,以及List<Person>,甚至List<Object>也是可以的。只要传递给printList()方法的List类型参数为Student,或者Student的父类型就是可以的。

你现在可以向list中添加Student类型的参数,例如:list.add(new Student())。因为用户提供的参数List<Student>、List<Person>、List<Object>,无论哪一种类型,对于list.add(new Student())都是合法的。

但是,现在我们不知道list的get()方法返回的是什么了!因为用户传递的可能是List<Student>、List<Person>、List<Object>,如果我们用Student s = list.get(0),那么如果list其实是一个List<Person>岂不是出错了!没错,只能使用Object来接收list.get(0)的返回值了。

?

4 无界通配符

所谓无界通配符,即List<?>,对通配符没有限定。你可以给List<?>赋任意的值,但是,你能使用这样的list干什么呢?也不能add(),也只能使用Object来接收get()方法返回值。

所以,通常List<?>只能表示你在使用泛型而已!编译器会认为List<?>比List更加优雅一些!你可能也看出来了,泛型还真是很垃圾!!!这也是没有办法中的办法,现在的泛型是迁移性兼容的一种版本而已!Java设计者不敢让JVM知道泛型的存在,原因是为了兼容1.4之前的版本。当所有人都在使用1.5以上版本的JDK后,Java的泛型可能就不会再是编译期状态了。

?

1.5新特性

自动装箱拆箱

?

1 什么是自动装箱拆箱

在1.5之后,Java允许把基本类型与其对应的包装器类型之间自动相互转换。例如:Integer i = 100,把int类型的100直接给了Integer类型的变量i,这就是自动装箱。int a = new Integer(100),这是自动拆箱。

Object o = 100;//其实是把100自动装箱为Integer,即Object o = Integer.valueOf(100)。

int a = (Integer)o;//其实是把o强转为Integer后,自动拆箱为int,即int a=((Integer)o).intValue()。

?

2 Integer.valueOf()与Integer内部缓存

我们已经知道自动装箱使用的是Integer.valueOf()方法,但我们要了解一下,其实valueOf()方法会使用Integer类内部的缓存来获取Integer对象。

Integer类的内部缓存了-128~127之间的256个Integer对象,如果valueOf()方法需要把这个范围之内的整数转换成Integer对象时,valueOf()方法不会去new对象,而是从缓存中直接获取,这就会导致valueOf(100)两次,都是从缓存中获取的同一个Integer对象!

Integer i1 = Integer.valueOf(100);

Integer i2 = Integer.valueOf(100);

boolean b = i1 == i2;//结果为true

?

相同的道理:

Integer i1 = 100;

Integer i2 = 100;

boolean b = i1 == i2;//结果为true

?

但是:

Integer i1 = 200;

Integer i2 = 200;

boolean b = i1 == i2;//结果为false

?

  这是因为200不在Integer内部的缓存之内,所以这时valueOf()方法会new一个Integer对象。每次valueOf(200)都会创建一个新的Integer对象,所以才会是false。

?

增强for

?

1 增强for循环概念

可以循环遍历数组或者集合类。

?

2 增强for循环的语法格式

for(元素类型 e : 数组或集合对象) {

}

增强for每循环一次,都会把数组或集合中的一个元素赋值给e,从头开始遍历,直到最后一个元素。

?

3 增强for的优缺点

只能从头到尾的遍历数组或集合,而不能只遍历部分。

在遍历List或数组时,不能获取当前元素下标。

增强for使用便简单,这是它唯一的优点了。

增强for比使用迭代器方便一点!

?

4 增强for与Iterable接口

  任何实现了Iterable接口的类,都可以使用增强for来遍历。

?

静态导入(鸡肋)

?

1 什么是静态导入

静态导入也需要使用import关键字;

静态导入后,在调用静态方法,以及使用静态属性时就可以不再给出类名了,例如向控制台打印时可以把System.out.println()写成out.println();System.exit(0)写成exit(0)。

?

2 静态导入的语法格式

import static 包名.类名.静态方法名;

import static 包名.类名.静态属性名;

import static 包名.类名.*;

?

3 静态导入真是鸡肋啊

不建议使用!

使用静态导入,使代码可读性降低!

?

可变参数

?

1 使用数组为方法参数

int sum(int a, int b) {return a + b;}

int sum(int a, int b, int c) {return a + b;}

int sum(int a, int b, int c, int d) {return a + b + c + d;}

?

看上面代码。我们知道这种重载是无止境的!

当函数的参数可以是0~n个时,我们最好的办法就是使用数组来处理,例如把上面代码修改为一个函数:

int sum(int[] arr) {

int sum = 0;

for(int i = 0; i < arr.length; i++) {

sum +=arr[i];

}

return sum;

}

?

修改后的sum()方法可以计算0~N个整数的和,但调用sum()需要传递一个数组,这使调用这个函数很不方便。

int arr = {1,2,3,,4,5,5};

sum(arr);

?

2 可变参数方法的定义

可以把数组类型的参数定义为可变参数,例如:

int sum(int[] arr) {

int sum = 0;

for(int i = 0; i < arr.length; i++) {

sum +=arr[i];

}

return sum;

}

int sum(int… arr) {

int sum = 0;

for(int i = 0; i < arr.length; i++) {

sum +=arr[i];

}

return sum;

}

?

上面代码把int[] arr修改为int… arr,其中arr就变成了可变参数。

可变参数其实就是数组。

?

3 调用可变参数方法

当调用int sum(int…arr)方法时就方便多了。如下方式的调用都是正确的:

?

  调用可变参数方法,可以传递0~N个参数来调用,也可以直接传递数组来调用。

?

4 可变参数方法的要求

可变参数只能出现在方法的形参中,局部变量或属性是不能使用这种东西的。

?

枚举

?枚举类型概述

?

1 什么是枚举类型

word文档的对齐方式有几种:左对齐、居中对齐、右对齐;

开车的方向有几种:前、后、左、右;

枚举就是有限实现个数的类型,你可能会说,byte类型也只有256个,没错,但我们真实定义为枚举的类型,一般最多也就十多个实例,再多就不会定义为枚举了。

?

2 JDK1.4之前的枚举类型

在JDK1.4之前没有枚举类型,都是使用int或字符串类型来表示枚举,如果枚举只有两个选项,那么连int都用不上,只需要使用boolean类型即可。

例如:BorderLayout类的方位给出五个:CENTER、EAST、SOUTH、WEST、NORTH。当使用容器类的方法添加组件时:add(new Button(), "CENTER"),这是合法的,但因为String类型太过宽泛,所以可能会出现add(new Button(), "哈哈")的调用可能,这会导致运行时出现异常。所以,JDK1.5又新增了枚举类型。

?

3 定义枚举类型

定义枚举类型需要使用enum关键字,例如:

public enum Direction {

FRONT、BEHIND、LEFT、RIGHT;

}

Direction d = Direction.FRONT;

?

注意,每个枚举选项之间是用逗号隔开的。如果枚举类没有构造器、方法等,在最后一个枚举选择后面可以不打分号。但是如果枚举类还有其他成员,那么就要在最后一个枚举项后面添加分号了。

Direction类型只有四个选项,你可以理解为这个枚举类只有四个实例对象一样。外界无法去创建新的枚举对象,只能从这四个中去选择。

其实大多数时候,我们使用枚举类型还是与以及使用int或String表示的枚举一样,基本上都是很简单的。

?

4 枚举与switch

1.5开始枚举类型可以在switch中使用!在1.7之后,String类型也可以放到switch中使用了。

????????Direction d = Direction.FRONT;

????????switch(d) {

????????case FRONT: System.out.println("前面");break;

????????case BEHIND:System.out.println("后面");break;

????????case LEFT: System.out.println("左面");break;

????????case RIGHT: System.out.println("右面");break;

????????????default:System.out.println("错误的方向");

????????}

????????Direction d1 = d;

????????System.out.println(d1);

?

  注意,在switch中,不能使用枚举类名称,例如:"case Direction.FRONT:"这是错误的,因为编译器会根据switch中d的类型来判定每个枚举类型,在case中必须直接给出与d相同类型的枚举选项,而不能再有类型。

?

枚举类也是类

?

1 所有枚举类都是Enum的子类

所有枚举类都默认是Enum类的子类,无需我们使用extends来继承。这说明Enum中的方法所有枚举类都可以的。

?

2 枚举类的构造器

  枚举类也可以有构造器,构造器不能给出访问修饰,而且默认都是private构造器。因为枚举类的实例不能让外界来创建!

enum Direction {

????FRONT, BEHIND, LEFT, RIGHT;

????

????Direction() {

????????System.out.println("hello");

????}

}

?

3 枚举类的方法

再次强调,枚举类也是类,也可以有构造器、方法和属性,只是对构造器有一些限制而已。在语法上有一些怪异罢了!

enum Direction {

????FRONT, BEHIND, LEFT, RIGHT;

????public void fun() {

????????System.out.println("hello Enum!");

????}

}

Direction.FRONT.fun();

?

4 枚举类的属性

枚举类也可以有属性。但是,如果每个枚举常量的属性值如果都相同,那就失去了意义,我们需要让每个枚举常量的属性值不同,那么就需要自己使用构造器来创建枚举常量,然后在构造器中给每个枚举常量传递不同的值。

enum Direction {

????FRONT("前面"), BEHIND("后面"), LEFT("左面"), RIGHT("右面");

????

????private String explain;

????

????Direction(String explain) {

????????this.explain = explain;

????}

????

????public void setExplain(String explain) {

????????this.explain = explain;

????}

?

????public String getExplain() {

????????return explain;

????}

}

????????String explain = Direction.FRONT.getExplain();

????????System.out.println(explain);

?

5 使用匿名类来创建枚举常量

  还可以使用匿名类来创建枚举常量,这说明枚举常量的类型是当前枚举类的子类,而且是个匿名类。这可以让每个枚举常量有自己的类型,当然有自己的类型不是目的,而是有自己的行为才是目的!但是我们知道就算给匿名类添加了自己独有的方法,也是无法调用的,因为匿名类没有名字,只能使用父类的引用指向匿名类的实例,而多态之后只能调用父类中存在的方法。所以,使用这种情况时,通常是为了让每个枚举常量重写当前枚举类中的方法(抽象方法)。

enum Direction {

????FRONT() {

????????public void fun() {

????????????System.out.println("FROND:重写了fun()方法");

????????}

????},

????BEHIND() {

????????public void fun() {

????????????System.out.println("BEHIND:重写了fun()方法");

????????}

????},

????LEFT() {

????????public void fun() {

????????????System.out.println("LEFT:重写了fun()方法");

????????}

????},

????RIGHT() {

????????public void fun() {

????????????System.out.println("RIGHT:重写了fun()方法");

????????}

????};

????

????public void fun() {

????????System.out.println("没有意义的方法");

????}

}

????????Direction.FRONT.fun();

????????Direction.BEHIND.fun();

????????Direction.LEFT.fun();

????????Direction.RIGHT.fun();

?

通常fun()方法应该定义为抽象的方法,因为每个枚举常量都会去重写它。

你无法把Direction声明为抽象类,但需要声明fun()方法为抽象方法。

enum Direction {

????FRONT() {

????????public void fun() {

????????????System.out.println("FROND:重写了fun()方法");

????????}

????},

????BEHIND() {

????????public void fun() {

????????????System.out.println("BEHIND:重写了fun()方法");

????????}

????},

????LEFT() {

????????public void fun() {

????????????System.out.println("LEFT:重写了fun()方法");

????????}

????},

????RIGHT() {

????????public void fun() {

????????????System.out.println("RIGHT:重写了fun()方法");

????????}

????};

????

????public abstract void fun();

}

?

枚举类的特殊方法

?

1 每个枚举类都有两个特殊方法

每个枚举类都有两个不用声明就可以调用的static方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方,下面是Direction类的特殊方法。

?

枚举的真实世界

?

1 枚举也是编译期状态

  其实枚举也是编译期状态,在运行时JVM并不知道什么是枚举类型。这也就是说,编译器需要把枚举类型转换成普通类。

enum Direction {FRONT, BEHIND, LEFT, RIGHT}

final class Direction extends Enum {

????public static final Direction FRONT;

????public static final Direction BEHIND;

????public static final Direction LEFT;

????public static final Direction RIGHT;

????private static final Direction ENUM$VALUES[];

?

????static {

????????FRONT = new Direction("FRONT", 0);

????????BEHIND = new Direction("BEHIND", 1);

????????LEFT = new Direction("LEFT", 2);

????????RIGHT = new Direction("RIGHT", 3);

????????ENUM$VALUES = new Direction[] {FRONT, BEHIND, LEFT, RIGHT};

????}

?

????private Direction(String s, int i) {

????????super(s, i);

????}

?

????public static Direction[] values() {

????????Direction adirection[];

????????int i;

????????Direction adirection1[];

????????System.arraycopy(adirection = ENUM$VALUES, 0,

????????????????adirection1 = new Direction[i = adirection.length], 0, i);

????????return adirection1;

????}

?

????public static Direction valueOf(String s) {

????????return (Direction) Enum.valueOf(Direction.class, s);

????}

}

?

反射

反射概述

?

1 什么是反射

让我们从Class类开始了解反射!

技术分享

每个加载到方法区中的class文件都对应一个Class类的对象,你可以把Class类的对象理解为硬盘上的class文件的对应体。

?

技术分享

2 反射的作用

反射是Java中的高级特性,在各种Java框架中都需要使用反射。所以,就算你将来很长一段时间不使用反射,但你使用的框架都大量使用了反射,所以想深入学习框架,那么就一定要学习反射。

框架通常通过反射来识别一个对象的"类型信息"。当你传递给框架一个对象时,框架会通过反射来了解对象的真实类型(对象实体的类型,而不是引用的类型),这个类型有几个构造器,有什么样的属性,有什么样的方法。还可以通过反射调用构造器,调用方法,对属性进行读写操作。

你可能觉得这没有什么神奇的,那是你还没了解我说的是什么!你需要再想一想,写一个方法,参数是Object obj,然后你的方法需要创建一个与参数类型相同的对象出来,还要调用这个对象上的方法。需要注意,参数是Object类型,但用户调用这个方法时,可能传递的不是Object实体对象,它的真实类型有可能是任何类型。

public static void fun(Object obj) {

}

?

3 猜猜Class类都有什么功能

我们学习面向对象也有一定的时间了,可以通过面向对象的思想,猜测一个类中应该有什么样的方法了。

一个Student类用来表示学生类型,学生应该有名字,那么学生类就应该有getName()方法。学生也应该有学号,那么学生类就应该有getNumber()方法…

一个Class类用来表示类类型,类应该有属性,那么Class类就应该有getField()方法,但一个类可以有多个属性,那么Class类有的就不是getField(),而是getFields()方法,返回值为Field[]类型。相同的道理,Class类也应该有getMethods()和getConstructors()方法,用来返回这个类的所有方法和所有构造器的定义。其实今后我们去学习,很可能就只是想使用一个类的一个方法!然后才去查找这个类,再去学习我们需要的方法,对于这个类的其他就一无所知了!你很可能在编写某个项目时会有这样的想法:某某某方法应该是某某某类的!!!然后你就去查找API!

描述学生的类型、描述老师的类型、描述计算机的类型,都是很好理解的,但描述类的类型总是让人感觉怪怪的,这也是初学者需要习惯的地方。还有,我们在学习过程中称呼这些类型时也需要注意一下,例如Field表示属性类,Field类有一个属性叫name,那么我们需要怎么说明这个name属性呢?"属性类的name属性",这是一个不错的称呼!

?

Class类

?

1 反射从Class类开始

要想使用反射,首先你需要得到Class对象,然后才能通过Class对象获取Constructor、Field、Method等对象。所有的反射对象都不可能自己来new,说白一点,这些反射对象对应的是class文件上的信息,你怎么可能自己去new呢?如果可以自己去new一个Class类的对象,那么是不是就不用我们再去编写.java文件,然后再通过编译器去编译成.class文件了呢?当然这是不可能的!

我们需要思考,Class除了可以返回当前对应类型的所有属性、方法、构造器的反射对象外,还有什么功能呢?例如对应类型的类名是什么?对应类型的父类是谁?对应类型是不是public类,是不是final类。对应类型有没有可能是个数组类型?有没有可能是接口类型?有没有可能是基本类型等等!如果你学会了这样思考,那么你今后学习新类是就方便多了!

?

2 得到Class对象

Class c1 = "".getClass();

Class c2 = String.class;

Class c3 = Class.forName("java.lang.String");

System.out.println(c1 == c2);

System.out.println(c2 == c3);

?

  上面代码输出的都是true,这是因为一个.class文件,在方法区中只对应一个Class对象。

?

3 加载类

我们已经知道,main()方法是程序的入口。那是不是在main()方法开始执行之前,所有的class文件都已经加载到方法区中了呢?答案是:NO!通常只有需要执行到使用某个类的代码时,才会去CLASSPATH中加载class文件,如果程序从头到尾都没有使用某个类,那么这个类对应的class文件就不会被加载到内存。

可以导致一个类被加载可能有:

上面给出的几个可能也只是可能而已,如果当前类没有被加载过,才会去加载,如果已经加载到方法区中了,那么就不可能再去加载。

?

4 Class类方法

  方法1:

?

方法2:

?

方法3:

?

方法4:

?

其他反射类

  其他反射类都在java.lang.reflect包下

1 AccessibleObject

AccessibleObject类是Constructor、Method、Field三个类的父类。

?

2 Construcator

?

3 Method

?

4 Field

?

5 Modifier

Modifier类有一系列的static方法用来解析其他getModifiers()方法返回的int值。

Method m = …

int m = m.getModifiers();

boolean b1 = Modifier.isAbstract(m);//解析m中是否包含abstract修饰

boolean b2 = Modifier.isStatic(m);//解析m中是否包含static修饰

String s = Modifiers.toString(m);//把所有修饰都转换成字符串

?

?

?

?

自学笔记:

?

day07

?

上节内容回顾

????1、schema约束

????

????2、sax解析原理

????????* 采用事件驱动,边读边解析

????????** 解析到开始标签时候,执行startElement方法

????????** 解析到文本时候,执行characters方法

????????** 解析到结束标签时候,执行endElement方法

?

???? dom的解析原理:

????????* 根据xml的层级结构在内存中分配一个树形结构

????????* 会把xml的标签、属性和内容,都封装成对象

????????

????3、dom4j解析xml

????????* 使用dom4j,第一步导入jar包

?

????????* 使用dom4j实现查询操作

????????????** element(""):获取第一个子标签

????????????** elements(""):获取相同名称的子标签

????????????** elements(): 获取所有的子标签

?

????????????** 获取标签里面的内容: getText方法

?

????????* 使用dom4j实现增加操作(在末尾添加)

????????????** 在p1上面执行addElement方法

????????????** 在标签上添加文本内容使用 setText方法

????????????** 回写xml

????????????????- 格式化 : OutputFormat...

????????????????- XMLWriter

????????????????- 执行write方法把document

????????????????- 关闭流

????????

????????* 使用dom4j实现增加操作(在特定为位置添加)

????????????** 首先获取到标签下面的所有的子标签

????????????** 返回list集合

????????????** list里面的方法 add(位置,"添加的元素")

????????????** list集合的位置从0开始的

????????

????????* 使用dom4j实现修改的操作

????????????** setText("内容")方法

????????

????????* 使用dom4j实现删除 操作

????????????** remove方法

????????????** 通过父节点删除

????????????????- getParent方法

????4、学生管理系统简单实现

????????* 实现增加操作

????????????- 通过对象传递进来

????????

????????* 删除操作

????????????- 通过id删除

????????????步骤:

????????????????1、获取所有的id

????????????????????- xpath //id

????????????????2、返回list集合

????????????????3、遍历list集合

????????????????4、得到每一个id的值

????????????????5、判断这两个id是否相同

????????????????6、如果相同,获取id的父节点

????????????????7、使用父节点删除

????????

????????* 查询操作

????????????- 通过id查询

????????????- 步骤:

????????????????1、获取所有的id

????????????????2、返回的list集合

????????????????3、遍历list集合

????????????????4、判断id是否相同

????????????????5、如果相同,获取相应的内容

?

1、myeclipse的安装和使用

????* eclipse:是一个免费的开发工具

????* myeclipse:是一个收费的插件,破解myeclipse,

????????** 安装目录的要求: 不能有中文和空格

????????** 安装完成之后,选择一个工作空间 ,这个工作空间不能有中文和空格

????* 破解myeclipse

????????** 运行run.bat文件,但是运行之前,必须要安装jdk,通过配置环境变量

?

????* myeclipse的使用

????????* 创建一个工程

????????????- 类型 java project web project

????????????- 选择依赖的jdk,可以使用myeclipse自带的jdk,或者可以使用安装的jdk

????????

????????* 创建包 package

????????????- cn.itcast.test XX.XX.XX

????????

????????* 在包里面创建一个类

????????????- 类的命名规范:

????????????????** 首字母要大写

????????????????????比如: TestDemo1 UserManager

????????

????????* 在类里面创建方法

????????????public void test1(参数列表) {

????????????????方法体或者返回值;

????????????}

????????????- 方法的命名规范

????????????????首字母小写 比如:addNum()

????????

????????* 定义变量

????????????- 变量的命名规范

????????????** 首字母小写,第二个单词的首字母要大写 ,比如 userName

????????

????????* 这些命名还有一种方式

????????????** 使用汉语拼音命名 yonghuming mima

????????????** 不能把汉语拼音和英文字母混合使用

????????????????userMing

?

????????* 命名的最基本的原则:看到名字知道是什么含义

?

????????* 代码需要有缩进

?

????????* 运行程序 run as java application

???????????? debug as java application

?

2、debug的调试模式(断点调试模式)

????* 使用这种模式,调试程序(看到程序里面数据的变化)

?

????* 使用debug第一步需要设置一个断点(让程序运行停止在这一行)

????????- 显示出来行号

????????- 双击左边,出现一个圆点,表示设置了一个断点

????* 使用debug as方式,运行程序

????????- 提示是否进入到调试界面,yes

????????- 在断点那一个,有一个绿色条,表示程序停止在这一行,没有向下运行

?

????* 可以让程序向下执行,

????????- 使用 step over 快捷键是 F6(单步执行)

????????- resume F8:表示调试结束,直接向下运行

????????????** 比如当前的断点之后还有断点,跳到下一个断点,

????????????** 如果当前断点后面没有断点,程序直接运行结束

????

????* debug另外一个用途

????????** 查看程序的源代码

????????** F5 step into:进入到方法

????????** F7 step return :返回

?

3、myeclipse的快捷键的使用

????* 代码提示 alt /

????* 快速导包 ctrl shift o

????* 单行注释 ctrl /

????* 去掉单行注释 ctrl /

????* 多行注释 ctrl shift /

????* 去掉多行注释 ctrl shift

????* 删除行 ctrl d

?

4、junit的使用

????* 单元测试

?

????* 测试对象是 是一个类中的方法

?

????* juint不是javase的一部分,想要使用导入jar包

????????** 但是,在myeclipse中自带了junit的jar包

????

????* 首先junit版本 3.x 4.x

????????* 单元测试方法时候,方法命名规则 public void 方法名() {}

????

????* 使用注解方式运行测试方法, 在方法的上面

????????** @Test:表示方法进行单元测试

?

????????--- @Test

????????????public void testAdd1() {

????????????????TestJunit test01 = new TestJunit();

????????????????test01.testAdd(2, 3);

????????????}

????????????- 选中方法名称,右键运行 点击run as --- junit test

????????????- 当出现绿色条,表示方法测试通过

????????????- 当出现了红棕色条,表示方法测试不通过

?

????????--- 要运行类中的多个测试方法,点击类中的其他位置,run as --- junit test

????

????????** @Ignore :表示这个方法不参与单元测试

?

????????** @Before: 在每个方法执行之前运行

????????** @After:在每个方法执行之后运行

?

????????** 断言(了解)

????????????- Assert.assertEquals("测试期望的值", "方法运行的实际的值")

????????

jdk5.0新特性

jdk 1.1 1.2 1.4 5.0

** 泛型、枚举、静态导入、自动拆装箱、增强for、可变参数

** 反射

?

5、泛型的简介

????* 为什么要使用泛型?

????????- 一般使用在集合上

????????** 比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放入到集合之后,失去本身的类型,只能是object类型,

????????这个时候,比如想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型来解决

????

????* 在集合上如何使用泛型

????????- 常用集合 list set map

????????- 泛型语法 集合<String> 比如 List<String>

????* 在泛型里面写是一个对象,String 不能写基本的数据类型 比如int (****)

????????** 写基本的数据类型对应包装类

????????????byte -- Byte

????????????short -- Short

?

????????????int -- Integer

?

????????????long -- Long

?

????????????float -- Float

????????????double -- Double

?

????????????char -- Character

?

????????????boolean -- Boolean

?

????* 在list上使用泛型

????????list的三种实现 ArrayList linkedList Vector

????????代码:

????????@Test

????????public void testList() {

????????????List<String> list = new ArrayList<String>();

????????????list.add("aaa");

????????????list.add("bbb");

????????????list.add("ccc");

?

????????????//遍历list集合 有几种方式 三种

????????????//普通for循环 迭代器 增强for

?

????????????//普通for循环

????????????for(int i=0;i<list.size();i++) {

????????????????String s = list.get(i);

????????????????System.out.println(s);

????????????}

?

????????????System.out.println("=================");

????????????//使用增强for

????????????for (String s1 : list) {

????????????????System.out.println(s1);

????????????}

?

????????????System.out.println("=================");

????????????//使用迭代器遍历

????????????Iterator<String> it = list.iterator();

????????????while(it.hasNext()) {

????????????????System.out.println(it.next());

????????????}

?

????????* 作业1: ArrayList linkedList Vector 这三个区别

?

????* 在set上使用泛型

????????代码:

????????//泛型使用set集合上

????????@Test

????????public void testSet() {

????????????Set<String> set = new HashSet<String>();

????????????set.add("www");

????????????set.add("qqq");

????????????set.add("zzz");

????????????//set.add("qqq");

????????????//遍历set 有几种方式 两种

????????????//迭代器 增强for

????????????//使用增强for遍历

????????????for (String s2 : set) {

????????????????System.out.println(s2);

????????????}

????????????System.out.println("=================");

????????????//使用迭代器遍历

????????????Iterator<String> it1 = set.iterator();

????????????while(it1.hasNext()) {

????????????????System.out.println(it1.next());

????????????}

????????}

????

????* 在map上面使用泛型

????????- map结构:key-valu形式

????????代码:

????????//在map上使用泛型

????????@Test

????????public void testMap() {

????????????Map<String,String> map = new HashMap<String,String>();

????????????map.put("aaa", "111");

????????????map.put("bbb", "222");

????????????map.put("ccc", "333");

????????????//遍历map 有几种遍历方式 两种

????????????// 1、获取所有的key,通过key得到value 使用get方法

????????????// 2、获取key和value的关系

????????????//使用第一种方式遍历

????????????//获取所有的key

????????????Set<String> sets = map.keySet();

????????????//遍历所有key返回的set

????????????for (String key : sets) {

????????????????//通过key得到value

????????????????String value = map.get(key);

????????????????System.out.println(key+" : "+value);

????????????}

????????????

????????????System.out.println("==============");

????????????//得到key和value的关系

????????????Set<Entry<String, String>> sets1 = map.entrySet();

????????????//遍历sets1

????????????for (Entry<String, String> entry : sets1) {

????????????????//entry是key和value关系

????????????????String keyv = entry.getKey();

????????????????String valuev = entry.getValue();

????????????????System.out.println(keyv+" : "+valuev);

????????????}

????????}

?

6、泛型使用在方法上

????* 定义一个数组,实现指定位置上数组元素的交换

????* 方法逻辑相同,只是数据类型不同,这个时候使用泛型方法

????* /*

???? * 使用泛型方法 需要定义一个类型 使用大写字母表示 T :这个T表示任意的类型

???? * 写在返回值之前 void之前 <T>

???? * =======表示定义了一个类型 这个类型是 T

???? * 在下面就可以使用这个类型了 T

???? * */

????

????public static <T> void swap1(T[] arr ,int a,int b) {

????????T temp = arr[a];

????????arr[a] = arr[b];

????????arr[b] = temp;

????}

?

????** 作业2: 实现一个泛型方法,接受任意一个数组,颠倒数组中所有元素

?

7、泛型在类上的使用(了解)

????* 在一个类上定义一个类型,这个类型可以在类里面直接使用

????* public class TestDemo04<T> {

????

????//在类里面可以直接使用T的类型

????T aa;

????public void test11(T bb) {}

????

????//写一个静态方法 在类上面定义的泛型,不能再静态方法里面使用

????public static <A> void test12(A cc) {}

????}

?

8、枚举的简介

????* 什么是枚举?

????????** 需要在一定的范围内取值,这个值只能是这个范围内中的任意一个。

????????** 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个

????

????* 使用一个关键字 enum

????** enum Color3 {

????????RED,GREEN,YELLOW;

????}

????* 枚举的构造方法也是私有的

?

????* 特殊枚举的操作(了解)

????** 在枚举类里面有构造方法

????????** 构造方法里面有参数,需要在每个实例上面都写参数

????** 在枚举类里面有抽象方法

????????** 在枚举的每个实例里面都重写这个抽象方法

?

9、枚举的api的操作

????** name() :返回枚举的名称

????** ordinal() :枚举的下标,下标从0开始

????** valueOf(Class<T> enumType, String name) :得到枚举的对象

?

????** 还有两个方法,都是这两个方法不在api里面,编译的时候生成两个方法

????*** valueof(String name) 转换枚举对象

????*** values() 获得所有枚举对象数组

?

????* 练习:枚举对象、枚举对象下标、枚举对象名称表示之间的转换

????- //知道枚举的对象,得到枚举名称和下标

????@Test

????public void test1() {

????????//得到枚举对象

????????Color100 c100 = Color100.RED;

????????//枚举名称

????????String name = c100.name();

????????//枚举的下标

????????int idx = c100.ordinal();

????????System.out.println(name+" "+idx);

????}

?

????- //知道枚举的名称,得到枚举的对象和下标

????@Test

????public void test2() {

????????String name1 = "GREEN";

????????//得到对象

????????Color100 c1 = Color100.valueOf(name1);

????????//枚举下标

????????int idx1 = c1.ordinal();

????????System.out.println(idx1);

????}

?

????- //知道枚举的下标,得到枚举的对象和名称

????@Test

????public void test3() {

????????int idx2 = 2;

????????//得到枚举的对象

????????Color100[] cs = Color100.values();

????????//根据下标得到对象

????????Color100 c12 = cs[idx2];

????????//得到枚举的名称

????????String name = c12.name();

????????System.out.println(name);

????}

?

10、静态导入(了解)

????* 可以在代码里面,直接使用静态导入方式,导入静态方法或者常量

????* import static XX.XX.xxx

?

????* import static java.lang.System.out;

????import static java.util.Arrays.sort;

?

????** 比如现在实现一个计算器 在Math类里面

?

11、自动拆装箱

????* 装箱

????????** 把基本的数据类型转换成包装类

????* 拆箱

????????** 把包装类转换成基本的数据类型

?

????** ????//自动装箱

????????Integer i = 10;

????????

????????//自动拆箱

????????int m = i;

????

????** 在jdk1.4里面如何实现装箱和拆箱

????????- //在jdk1.4里面实现拆装箱

????????public void test1() {

????????????//装箱

????????????Integer m = new Integer(10);????????

????????????//拆箱????

????????????int a = m.intValue();

????????}

????** jdk是会向下兼容

????????- 比如 jdk1.4里面写的代码,这个时候到5.0里面也可以运行

?

????** 练习:向下兼容

????== 执行的结果是会调用 doSomething(double m)

????== 首先在jdk1.4里面肯定调用这个方法,如果调用下面的方法,需要类型转换,但是jdk1.4不能实现自动拆装箱

????== 由于jdk是向下兼容,所以,在jdk1.4调用这个方法,在jdk5.0里面还是会调用这个方法

????????public static void main(String[] args) {

????????????doSomething(10);

?

????????}

????????

????????public static void doSomething(double m) {

????????????System.out.println("double......");

????????}

????????

????????public static void doSomething(Integer a){

????????????System.out.println("integer.....");

????????}

????** 记住:八种基本的数据类型对应的包装类

????????* int --- Integer

????????* char--- Character

?

12、增强for循环(*****)

????* 语法 for(遍历出来的值 : 要遍历的集合) {}

????????- for(String s : list) {

????????????System.out.println(s);

????????}

????* 使用场景: 数组;实现Iterable接口的集合 可以使用增强for循环

?

????* 在集合上使用增强for循环遍历

????????list set 实现了Iterator接口,所以可以使用增强for循环

????????map不能使用增强for循环,没有实现Iterator接口,所以不能使用增强for循环

?

????* 增强for循环出现目的:为了替代迭代器

????????** 增强for底层就是迭代器实现的

????

13、内容补充

????(1)泛型擦除

????????* 首先泛型只是出现在源代码阶段,当源代码编译之后泛型就不存在了

????

????(2)练习:实现一个泛型方法,接受任意类型的数组,颠倒数组中所有元素

????代码

????public static <T> void reverses(T[] arr1) {

????????/*

???????? * 基本思想:把第一个元素和最后一个元素交换位置,把第二个元素和倒数第二个元素交换位置。。。。

???????? * 交换 长度/2

???????? * */

????????//遍历数组

????????for(int i=0;i<arr1.length/2;i++) {

????????????/*int temp = arr1[0];

????????????arr1[0] = arr1[arr1.length-1];*/

????????????T temp = arr1[i];

????????????arr1[i] = arr1[arr1.length-i-1];

????????????arr1[arr1.length-i-1] = temp;

????????}

????????

????}

?

14、可变参数

????* 可变参数可以应用在什么场景:

????** 实现两个数的相加,实现三个数的相加 四个数的相加

????-- 如果在实现的多个方法中,这些方法里面的逻辑基本相同,唯一不同的是传递的参数的个数,可以使用可变参数

?

????* 可变参数的定义方法: 数据类型...数组的名称

????* 理解为一个数组,这个数组存储传递过来的参数

????- 代码

????????public static void add1(int...nums) {

????????????//nums理解为一个数组,这个数组存储传递过来的参数

????????????//System.out.println(nums.length);

????????????int sum = 0;

????????????//遍历数组

????????????for(int i=0;i<nums.length;i++) {

????????????????sum += nums[i];

????????????}

????????????System.out.println(sum);

?

????????}

????

????* 注意的地方

????????(1)可变参数需要写在方法的参数列表中,不能单独定义

????????(2)在方法的参数列表中只能有一个可变参数

????????(3)方法的参数列表中的可变参数,必须放在参数最后

????????????- add1(int a,int...nums)

?

15、反射的原理(********理解********)

????* 应用在一些通用性比较高的代码 中

????* 后面学到的框架,大多数都是使用反射来实现的

?

????* 在框架开发中,都是基于配置文件开发

????????** 在配置文件中配置了类,可以通过反射得到类中的 所有内容,可以让类中的某个方法来执行

?

????* 类中的所有内容:属性、没有参数的构造方法、有参数的构造方法、普通方法

????

????* 画图分析反射的原理

????????* 首先需要把java文件保存到本地硬盘 .java

????????* 编译java文件,形成.class文件

????????* 使用jvm,把class文件通过类加载加载到内存中

????????* 万事万物都是对象,class文件在内存中使用Class类表示

?

????????* 当使用反射时候,首先需要获取到Class类,得到了这个类之后,就可以得到class文件里面的所有内容

????????????- 包含属性 构造方法 普通方法

????????* 属性通过一个类 Filed

????????* 构造方法通过一个类 Constructor

????????* 普通方法通过一个类 Method

?

16、使用反射操作类里面的无参数的构造方法(**会写**)

????* 首先获取到Class类

????????- // 获取Class类

????????Class clazz1 = Person.class;

????????Class clazz2 = new Person().getClass();

????????Class clazz3 = Class.forName("cn.itcast.test09.Person");

?

????* 比如: 要对一个类进行实例化,可以new,不使用new,怎么获取?

????????- //得到Class

????????Class c3 = Class.forName("cn.itcast.test09.Person");

????????//得到Person类的实例

????????Person p = (Person) c3.newInstance();

????* 代码

????//操作无参数的构造方法

????@Test

????public void test1() throws Exception {

????????//得到Class

????????Class c3 = Class.forName("cn.itcast.test09.Person");

????????//得到Person类的实例

????????Person p = (Person) c3.newInstance();

????????//设置值

????????p.setName("zhangsan");

????????System.out.println(p.getName());

????}

?

17、使用反射操作有参数的构造方法(**会写**)

????//操作有参数的构造方法

????@Test

????public void test2() throws Exception {

????????//得到Class

????????Class c1 = Class.forName("cn.itcast.test09.Person");

????????//使用有参数的构造方法

????????//c1.getConstructors();//获取所有的构造方法

????????//传递是有参数的构造方法里面参数类型,类型使用class形式传递

????????Constructor cs = c1.getConstructor(String.class,String.class);

????????//通过有参数的构造方法设置值

????????//通过有参数的构造方法创建Person实例

????????Person p1 = (Person) cs.newInstance("lisi","100");

????????System.out.println(p1.getId()+" "+p1.getName());

????}

?

18、使用反射操作属性(**会写**)

????* //操作name属性

????@Test

????public void test3() {

????????try {

????????????//得到Class类

????????????Class c2 = Class.forName("cn.itcast.test09.Person");

????????????//得到name属性

????????????//c2.getDeclaredFields();//表示得到所有的属性

????????????//得到Person类的实例

????????????Person p11 = (Person) c2.newInstance();

????????????//通过这个方法得到属性,参数是属性的名称

????????????Field f1 = c2.getDeclaredField("name");

????????????//操作的是私有的属性,不让操作,需要设置可以操作私有属性setAccessible(true),可以操作私有属性

????????????f1.setAccessible(true);

????????????//设置name值 set方法,两个参数:第一个参数类的实例,第二个参数是设置的值

????????????f1.set(p11, "wangwu"); //相当于 在 p.name = "wangwu";

????????????System.out.println(f1.get(p11)); //相当于 p.name

????????}catch(Exception e) {

????????????e.printStackTrace();

????????}

????}

?

19、使用泛型操作普通方法(**会写**)

????* 使用Method类表示普通方法

????* 代码

????//操作普通方法 ,比如操作 setName

????@Test

????public void test4() throws Exception {

????????//得到Class类

????????Class c4 = Class.forName("cn.itcast.test09.Person");

????????//得到Person实例

????????Person p4 = (Person) c4.newInstance();

????????//得到普通方法

????????//c4.getDeclaredMethods();//得到所有的普通方法

????????//传递两个参数:第一个参数,方法名称;第二个参数,方法里面参数的类型

????????Method m1 = c4.getDeclaredMethod("setName", String.class);

????????//让setName方法执行 ,执行设置值

????????//使用invoke(p4, "niuqi");传递两个参数:第一个参数,person实例;第二个参数,设置的值

????????//执行了invoke方法之后,相当于,执行了setName方法,同时通过这个方法设置了一个值是niuqi

????????m1.invoke(p4, "niuqi");

????????System.out.println(p4.getName());

????}

????

????* //操作的私有的方法 ,需要设置值是true

????* //m1.setAccessible(true);

?

????* 当操作的方法是静态的方法时候,因为静态方法调用方式是 类名.方法名,不需要类的实例

????* 使用反射操作静态方式时候,也是不需要实例的

????* 在invoke方法的第一个参数里面,写一个 null

????????- m1.invoke(null, "niuqi");

?

?

?

?

?

?

?

?

?

?

?

?

?

Day07 jdk5.0新特性&Junit&反射

原文:http://www.cnblogs.com/Prozhu/p/5719724.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!