Day07 jdk5.0新特性&Junit&反射
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快捷键
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>()。
在泛型类中可以使用类型变量:
当用户创建A类对象时,就会给A类的类型变量T赋值,例如:new A<String>(),这说明在A类中所有的T都会被String替换。
3 类型变量的限制
注意,你不能使用T类型的构造器:new T(),因为你不能确定t的类型,那么也就不知道它有什么样的构造器,甚至是否有public构造器,所以不能创建。
相同的道理,也不能创建T类型的属性,例如:new T[10],这也是不行的!
还有一点,在泛型类中,static方法中不能使用类型变量T。
继承(实现)泛型类(接口)
1 继承泛型类之一
如果当前类是泛型类,那么在继承(实现)泛型类(接口)时,可以把自己的类型变量传递给父类(接口)。
public class ArrayList<E> implements List<E> {
ArrayList<String> arr = new ArrayList<String>();
在用户创建ArrayList类对象时,传递给ArrayList类中的E的值是String,那么ArrayList会把这个String再传递给List中的E。
2 继承泛型类之二
泛型类的子类不一定必须为泛型类,也可以是非泛型类。这时因为子类没有类型变量可以传递给父类,那么也就能传递给父类类型常量了。
public class String implements Comparable<String> {
public int compareTo(String other) {…}
这时,在重写父类中方法时,所有的类型变量都是String了。
泛型方法
1 泛型方法定义
泛型类是说明这个类有类型变量,在创建这个类对象时需要给类型变量赋值。泛型方法是说明这个方法有类型变量,在调用这个方法时需要给类型变量赋值。
public <T> T get(T[] ts, int index) {
get()方法是一个泛型方法,它有一个类型变量T,这说明在调用get()方法时需要给get()方法的T赋值。
上面代码中给get()方法的类型变量T赋值为String,因为传递的参数为String数组,所以就是给T赋值为String。
当然,也可以显示给出类型变量的值:o.<String>get(strs,0),在点后面,方法名前面给出类型值,但一般人不会这么打代码。
泛型的边界
编译期状态:编译期状态,例如内部类!内部类就是只有编译器知道,而JVM不知道什么叫内部类!
1 泛型的擦除
泛型其实是编译期状态,即JVM不知道什么是泛型,在JVM那里所有类都是正常的类。没有类型变量。一切的一切都是编译器干的好事儿!
也就是说,在ArrayList类中持有的还是Object类型,而不是我们指定的类型。当然,就算是JVM没有泛型,但编译器会帮我们完成这些问题,我们就可以当泛型真的存在。
2 泛型边界限定的类型值的范围
通常我们看到的泛型类都没有边界限定,也就是说可以给泛型类的类型变量赋任意类型的值(当然基本类型是不可以的)。
java允许给类型变量指定边界,这样用户在给类型变量赋值时就必须在边界之内。
通配符
1 通配符的作用
Object[] objs = new String[10];
上面代码编译是可以通过的,但在运行时会出现ArrayStoreException。因为objs数组真实的身份是String[],向String[]数组中存放Integer对象当然是不行的。
ArrayList<Object> list = new ArrayList<String>();
public static void printList(List<Object> list) {…}
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子类型就都可以。
3 父类型通配符
public static void printList(List<? super Student> list) {…}
4 无界通配符
所谓无界通配符,即List<?>,对通配符没有限定。你可以给List<?>赋任意的值,但是,你能使用这样的list干什么呢?也不能add(),也只能使用Object来接收get()方法返回值。
1.5新特性
自动装箱拆箱
1 什么是自动装箱拆箱
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 i1 = Integer.valueOf(100);
Integer i2 = Integer.valueOf(100);
boolean b = i1 == i2;//结果为true
boolean b = i1 == i2;//结果为true
boolean b = i1 == i2;//结果为false
这是因为200不在Integer内部的缓存之内,所以这时valueOf()方法会new一个Integer对象。每次valueOf(200)都会创建一个新的Integer对象,所以才会是false。
增强for
1 增强for循环概念
2 增强for循环的语法格式
增强for每循环一次,都会把数组或集合中的一个元素赋值给e,从头开始遍历,直到最后一个元素。
3 增强for的优缺点
4 增强for与Iterable接口
任何实现了Iterable接口的类,都可以使用增强for来遍历。
静态导入(鸡肋)
1 什么是静态导入
2 静态导入的语法格式
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()需要传递一个数组,这使调用这个函数很不方便。
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 什么是枚举类型
枚举就是有限实现个数的类型,你可能会说,byte类型也只有256个,没错,但我们真实定义为枚举的类型,一般最多也就十多个实例,再多就不会定义为枚举了。
2 JDK1.4之前的枚举类型
在JDK1.4之前没有枚举类型,都是使用int或字符串类型来表示枚举,如果枚举只有两个选项,那么连int都用不上,只需要使用boolean类型即可。
3 定义枚举类型
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); |
枚举类也是类
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文件的对应体。
2 反射的作用
反射是Java中的高级特性,在各种Java框架中都需要使用反射。所以,就算你将来很长一段时间不使用反射,但你使用的框架都大量使用了反射,所以想深入学习框架,那么就一定要学习反射。
public static void fun(Object obj) {
3 猜猜Class类都有什么功能
我们学习面向对象也有一定的时间了,可以通过面向对象的思想,猜测一个类中应该有什么样的方法了。
一个Student类用来表示学生类型,学生应该有名字,那么学生类就应该有getName()方法。学生也应该有学号,那么学生类就应该有getNumber()方法…
Class类
1 反射从Class类开始
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 加载类
上面给出的几个可能也只是可能而已,如果当前类没有被加载过,才会去加载,如果已经加载到方法区中了,那么就不可能再去加载。
4 Class类方法
其他反射类
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);//把所有修饰都转换成字符串 |
* myeclipse:是一个收费的插件,破解myeclipse,
** 安装完成之后,选择一个工作空间 ,这个工作空间不能有中文和空格
** 运行run.bat文件,但是运行之前,必须要安装jdk,通过配置环境变量
- 选择依赖的jdk,可以使用myeclipse自带的jdk,或者可以使用安装的jdk
** 首字母小写,第二个单词的首字母要大写 ,比如 userName
* 运行程序 run as java application
* 使用debug第一步需要设置一个断点(让程序运行停止在这一行)
- 在断点那一个,有一个绿色条,表示程序停止在这一行,没有向下运行
* juint不是javase的一部分,想要使用导入jar包
** 但是,在myeclipse中自带了junit的jar包
* 单元测试方法时候,方法命名规则 public void 方法名() {}
TestJunit test01 = new TestJunit();
- 选中方法名称,右键运行 点击run as --- junit test
--- 要运行类中的多个测试方法,点击类中的其他位置,run as --- junit test
- Assert.assertEquals("测试期望的值", "方法运行的实际的值")
** 泛型、枚举、静态导入、自动拆装箱、增强for、可变参数
** 比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放入到集合之后,失去本身的类型,只能是object类型,
这个时候,比如想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型来解决
- 泛型语法 集合<String> 比如 List<String>
* 在泛型里面写是一个对象,String 不能写基本的数据类型 比如int (****)
list的三种实现 ArrayList linkedList Vector
List<String> list = new ArrayList<String>();
for(int i=0;i<list.size();i++) {
System.out.println("=================");
System.out.println("=================");
Iterator<String> it = list.iterator();
System.out.println(it.next());
* 作业1: ArrayList linkedList Vector 这三个区别
Set<String> set = new HashSet<String>();
System.out.println("=================");
Iterator<String> it1 = set.iterator();
System.out.println(it1.next());
Map<String,String> map = new HashMap<String,String>();
// 1、获取所有的key,通过key得到value 使用get方法
Set<String> sets = map.keySet();
System.out.println(key+" : "+value);
System.out.println("==============");
Set<Entry<String, String>> sets1 = map.entrySet();
for (Entry<String, String> entry : sets1) {
String valuev = entry.getValue();
System.out.println(keyv+" : "+valuev);
* 使用泛型方法 需要定义一个类型 使用大写字母表示 T :这个T表示任意的类型
public static <T> void swap1(T[] arr ,int a,int b) {
** 作业2: 实现一个泛型方法,接受任意一个数组,颠倒数组中所有元素
* public class TestDemo04<T> {
//写一个静态方法 在类上面定义的泛型,不能再静态方法里面使用
public static <A> void test12(A cc) {}
** 需要在一定的范围内取值,这个值只能是这个范围内中的任意一个。
** 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个
** valueOf(Class<T> enumType, String name) :得到枚举的对象
** 还有两个方法,都是这两个方法不在api里面,编译的时候生成两个方法
*** valueof(String name) 转换枚举对象
* 练习:枚举对象、枚举对象下标、枚举对象名称表示之间的转换
System.out.println(name+" "+idx);
Color100 c1 = Color100.valueOf(name1);
Color100[] cs = Color100.values();
* 可以在代码里面,直接使用静态导入方式,导入静态方法或者常量
* import static java.lang.System.out;
import static java.util.Arrays.sort;
- 比如 jdk1.4里面写的代码,这个时候到5.0里面也可以运行
== 执行的结果是会调用 doSomething(double m)
== 首先在jdk1.4里面肯定调用这个方法,如果调用下面的方法,需要类型转换,但是jdk1.4不能实现自动拆装箱
== 由于jdk是向下兼容,所以,在jdk1.4调用这个方法,在jdk5.0里面还是会调用这个方法
public static void main(String[] args) {
public static void doSomething(double m) {
System.out.println("double......");
public static void doSomething(Integer a){
System.out.println("integer.....");
* 使用场景: 数组;实现Iterable接口的集合 可以使用增强for循环
list set 实现了Iterator接口,所以可以使用增强for循环
map不能使用增强for循环,没有实现Iterator接口,所以不能使用增强for循环
* 首先泛型只是出现在源代码阶段,当源代码编译之后泛型就不存在了
(2)练习:实现一个泛型方法,接受任意类型的数组,颠倒数组中所有元素
public static <T> void reverses(T[] arr1) {
* 基本思想:把第一个元素和最后一个元素交换位置,把第二个元素和倒数第二个元素交换位置。。。。
for(int i=0;i<arr1.length/2;i++) {
arr1[0] = arr1[arr1.length-1];*/
arr1[i] = arr1[arr1.length-i-1];
-- 如果在实现的多个方法中,这些方法里面的逻辑基本相同,唯一不同的是传递的参数的个数,可以使用可变参数
public static void add1(int...nums) {
//System.out.println(nums.length);
for(int i=0;i<nums.length;i++) {
** 在配置文件中配置了类,可以通过反射得到类中的 所有内容,可以让类中的某个方法来执行
* 类中的所有内容:属性、没有参数的构造方法、有参数的构造方法、普通方法
* 万事万物都是对象,class文件在内存中使用Class类表示
* 当使用反射时候,首先需要获取到Class类,得到了这个类之后,就可以得到class文件里面的所有内容
Class clazz2 = new Person().getClass();
Class clazz3 = Class.forName("cn.itcast.test09.Person");
* 比如: 要对一个类进行实例化,可以new,不使用new,怎么获取?
Class c3 = Class.forName("cn.itcast.test09.Person");
Person p = (Person) c3.newInstance();
public void test1() throws Exception {
Class c3 = Class.forName("cn.itcast.test09.Person");
Person p = (Person) c3.newInstance();
System.out.println(p.getName());
public void test2() throws Exception {
Class c1 = Class.forName("cn.itcast.test09.Person");
//c1.getConstructors();//获取所有的构造方法
//传递是有参数的构造方法里面参数类型,类型使用class形式传递
Constructor cs = c1.getConstructor(String.class,String.class);
Person p1 = (Person) cs.newInstance("lisi","100");
System.out.println(p1.getId()+" "+p1.getName());
Class c2 = Class.forName("cn.itcast.test09.Person");
//c2.getDeclaredFields();//表示得到所有的属性
Person p11 = (Person) c2.newInstance();
Field f1 = c2.getDeclaredField("name");
//操作的是私有的属性,不让操作,需要设置可以操作私有属性setAccessible(true),可以操作私有属性
//设置name值 set方法,两个参数:第一个参数类的实例,第二个参数是设置的值
f1.set(p11, "wangwu"); //相当于 在 p.name = "wangwu";
System.out.println(f1.get(p11)); //相当于 p.name
public void test4() throws Exception {
Class c4 = Class.forName("cn.itcast.test09.Person");
Person p4 = (Person) c4.newInstance();
//c4.getDeclaredMethods();//得到所有的普通方法
//传递两个参数:第一个参数,方法名称;第二个参数,方法里面参数的类型
Method m1 = c4.getDeclaredMethod("setName", String.class);
//使用invoke(p4, "niuqi");传递两个参数:第一个参数,person实例;第二个参数,设置的值
//执行了invoke方法之后,相当于,执行了setName方法,同时通过这个方法设置了一个值是niuqi
System.out.println(p4.getName());