1.泛型的擦除
泛型只存在于源代码阶段,当编译过后,编译文件中不存在泛型
2.可变参数
应用场景:当多个方法逻辑相同,但是参数不同的时候
可变参数的定义:数据类型…数组的名称
注意:可变参数需要写在方法的参数列表中,不能单独定义
在方法的参数列表中只能有一个可变参数
方法中参数列表的可变参数必须要放到最后test2(int a,int...num)
public class Testmap {
public static void main(String[] args) {
test1(10,20,30);
}
//遍历map的方式一
public static void test1(int...num){
//num可以看作一个数组,这个数组用来存储传递过来的参数
int sum=0;
for(int i=0;i<num.length;i++){
sum +=num[i];
}
System.out.println(sum);
}
}
3、反射
应用在一些通用性比较高的代码中,比如框架,大多数框架是使用反射来实现的。
在框架开发中都是基于配置文件的开发,在配置文件中设置了类,可以通过反射来得到类中的所有内容,可以让类中的某个方法来执行
类中的所有内容:属性、没有参数的构造方法、有参数的构造方法,普通的方法
反射的原理:首先是把源文件编译成字节码文件,然后在jvm上运行,会把字节码文件使用类加载器加载到内存中,在java中会有一个类来对内存中的字节码文件有一个表达就是Class类,如果得到了这个Class类,就可以得到类中的所有内容。
使用反射首先要得到Class类,有三种方法:(1)、类名.class (2)、对象.getClass();(3)、使用class.forName(“类的路径,即包名加类名”);
得到类就得到了所有内容,而这些内容也有相应的类来表示。属性—Field,构造方法—Constructor,普通方法——Method。
获取一个类额实例,可以new,也可以不new,不使用new就是通过反射来获取。
public static void test1() throws Exception{
//得到Class类
Class c3 = Class.forName("cn.liqing.junit.Person");
//得到Person类的实例
Person p = (Person) c3.newInstance();
}
有关操作,代码
Person.java
package cn.liqing.junit;
public class Person {
//属性
private String name;
private int age;
//构造方法
public Person(){
}
//普通方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
TestFs.java
package cn.liqing.junit;
import java.lang.reflect.Constructor;
import org.junit.Test;
public class TestFs {
public static void main(String[] args) throws Exception {
//获取Class类,3种方式
Class class1 = Person.class;
Class class2 = new Person().getClass();
//下面这种方式用的最多
Class class3 = Class.forName("cn.liqing.junit.Person");
}
@Test
//操作无参构造方法
public void test1() throws Exception{
//得到Class类
Class c3 = Class.forName("cn.liqing.junit.Person");
//得到Person类的实例
Person p = (Person) c3.newInstance();
p.setName("liqing");
System.out.println(p.getName());
}
@Test
//操作无参构造
public void test2() throws Exception{
//得到Class类
Class c4 = Class.forName("cn.liqing.junit.Person");
c4.getConstructors();//获取所有的有参构造
//使用获取一个有参构造的方法,需要传递的是一个可变参数,这里面需要传递的是有参数构造方法里面的参数类型
//类型使用class形式传递
Constructor cs = c4.getConstructor(String.class,int.class);
//获取Person的实例,里面传的是与构造方法对应的参数
Person p2 = (Person) cs.newInstance("liqing",20);
System.out.println(p2.getName()+"--"+p2.getAge());
}
@Test
//操作属性
public void test3(){
//得到Class类
try {
Class c5 = Class.forName("cn.liqing.junit.Person");
//c5.getDeclaredFields();//获取所有的属性
Field field1 = c5.getDeclaredField("name");
//获取Person实例
Person p5 = (Person) c5.newInstance();
//field中set表示为属性设置值,第一个参数是要设置值得实例,第二个要为属性设置的值
//因为属性是私有的,所以需要设置,如果不设置,会出现错误
field1.setAccessible(true);//设置私有的属性值也可以操作
field1.set(p5, "liqing");
//得到属性的值使用get(),里面传递的也是要获得的对象的实例
System.out.println(field1.get(p5));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
//操作普通方法
public void test4() throws Exception{
//得到Class
Class c6 = Class.forName("cn.liqing.junit.Person");
//得到Person实例
Person p6 = (Person) c6.newInstance();
//得到普通方法
//c6.getDeclaredMethods();//得到所有的普通方法
//下面这个方法里要传递的第一个是要操作的普通方法名称,第二个是要操作的方法里的参数的类型,使用class形式
//如果要操作的方法是私有的,需要设置下面代码
field1.setAccessible(true);
Method m6 = c6.getDeclaredMethod("setName",String.class);
//Method中有一个方法,是设置值,并执行这个方法,第一个参数值要操作的对象的实例,第二个是要为方的参数设置的值
m6.invoke(p6, "liqing");
System.out.println(p6.getName());
}
}
当操作的方法是静态方法时,因为静态方法的调用的方式是类名.方法名,不需要类的实例,
使用反射操作时不需要静态实例,在invoke方法中的第一个参数里写null,m1.invoke(null,”liqing”)