1.泛型
1.1 泛型定义
将某一个类/接口/方法/变量的数据类型象使用参数一样传递给类/接口/方法/变量。
数据类型的参数化,任意化。
1.2 为什么需要泛型?
第一天 类中的x,y变量需要int
public class Test1{
private int x;
private int y;
}
第二天 类中的x,y变量需要double ,我们创建一个新类修改了一下x,y变量数据类型
public class Test2{
private double x;
private double y;
}
第三天 类中的x,y变量需要String ,我们创建一个新类修改了一下x,y变量数据类型
public class Test3{
private String x;
private String y;
}
第四天 类中的x,y变量需要char ,我们创建一个新类修改了一下x,y变量数据类型
......
当我们需要很多个业务逻辑相似,但是数据类型不同的java类时,我们又不想创建出多个业务逻辑相似,但是数据类型不同的java类。
我们就会想能不能用一个类把业务逻辑相似,但是数据类型不同的多个java类,统一一下
要解决这个统一问题我们就会首先处理数据类型的统一,要处理数据类型的统一,我们就会想到java.lang.Object类。
public class ObjectTest {
private Object x;
private Object y;
public Object getX() {
return x;
}
public void setX(Object x) {
this.x = x;
}
public Object getY() {
return y;
}
public void setY(Object y) {
this.y = y;
}
}
ObjectTest o=new ObjectTest();
//o.setX(180);
//o.setY(36);
//将x,y变量改成String
o.setX("一百八十");
o.setY("三十六");
System.out.println(o.getX()+","+o.getY());
//类型转换
// java.lang.ClassCastException
int sum=(Integer)(o.getX())+(Integer)(o.getY());
System.out.println(sum);
虽然我们可以使用Object来统一数据类型,但是在使用的时候需要进行强制类型转换.
如果转换不当会出现类型转换异常java.lang.ClassCastException。
这时我们就会想我们能不能把数据类型,如参数一样传递给我们需要使用的java类,这要我们既可以统一类型,可以避免强制类型转换。
泛型就被研究出来,解决上面的问题。
1.3 如何创建一个泛型类/泛型接口
在创建类的时候为类名后面添加一个“<>”,给”<>”中添加单个的大写字母,用来接收具体的某个数据类型。
”<>”中的单个的大写字母可以出现多个,中间使用”,”分割。
类中需要数据类型的部分可以使用单个的大写字母来代替,这是我们我们创建类的时候就可以传递具体的数据类型给单个的大写字母,类中需要数据类型的部分全部都会变成我们传递具体的数据类型。
public class Test1<I,S> {
private I x;
private S y;
public I getX() {
return x;
}
public void setX(I x) {
this.x = x;
}
public S getY() {
return y;
}
public void setY(S y) {
this.y = y;
}
}
public static void main(String[] args) {
Test1<Integer,String> t1=new Test1<Integer,String>();
t1.setX(180);
int x=t1.getX();
t1.setY("三十六");
String y=t1.getY();
}
1.4 泛型类/接口如何使用?
我们一般很少创建与泛型有关的元素,我们会经常使用jdk提供的开发包中的泛型类/接口。
1.使用泛型类创建对象的时候需要传递具体的数据类型
Test1 t1=new Test1(); //不合法的,会产生警告信息
Test1<Integer,String> t1=new Test1<Integer,String>(); //正确的
2.基本数据类型在被作为泛型的数据类型时,是不被允许的,可以使用应基本类型对应的封装类型代替
Test1<int,String> t1=new Test1<int,String>(); //错误
Test1<Integer,String> t1=new Test1<Integer,String>();//正确
3.当我们创建泛型对象的时候,没有传递指定的数据类型默认是Object类型。并伴随有警告信息出现
public static void main(String[] args) {
Student stu1=new Student(1001,"zhangsan");
Student stu2=new Student(1002,"lisi");
Student stu3=new Student(1003,"wangwu");
List stulist=new ArrayList();
stulist.add(stu1);
stulist.add(stu2);
stulist.add(stu3);
for(Object obj:stulist){
Student stu=(Student)obj;
System.out.println(stu.getStuid()+","+stu.getStuname());
}
}
之前学习过的类,他们其实是泛型类
java.util Class ArrayList<E>
java.util Class HashMap<K,V>
java.util Class Hashtable<K,V>
之前学习过的接口,他其实是泛型接口
java.util Interface Map<K,V>
public interface List<E>
public interface Collection<E>
2.反射
2.1 反射定义和作用
在程序运行的过程中,我们可以得到某个类的对象,可以调用某个类中的任何一个变量和方法,这种动态获取信息的过程就是反射。
作用:当我们在没有见过某个类的情况下,仅凭一个完整的类名【包名+类名】,就可以获取到整个类的所有方法和变量信息,比如访问类名,访问限制修饰符,返回值,异常类型,参数等,但是方法体里面是得不到的。
反射的使用场景:
1、jdbc加载数据库驱动
2、Servlet的web.xml配置
3、Spring框架
2.2 实例对象和反射对象的相互转换
反射对象:通过反射机制得到的类的对象,反射对象是一个Class类型的对象。【注意区别class关键字】
class---创建类的关键字
Class---类的类名,创建出来的Class类的对象就是反射对象。
public final class Class<T>
实例对象:目前我们学过得到类的实例对象有三种方式(new,静态方法,反射)。
(1)通过实例对象得到反射对象
通过实例对象的getClass()得到,当前实例对象对应的反射对象
通过Class类的forname(类名【包名+类名】)
(2)通过反射对象得到实例对象
反射对象的newInstance()方法,可以得到实例对象
package com.weiwei.test1;
public class Main {
public static void main(String[] args) throws Exception{
/*
//得到反射对象两种方式
// 1.通过实例对象得到反射对象
Student stu=new Student();//得到实例对象
Class classstu1 = stu.getClass();//得到反射对象
//2.通过Class类的forname(类名【包名+类名】)
Class classstu2 = Class.forName("com.weiwei.test1.Student");
*/
//通过反射对象得到实例对象
//反射对象的newInstance()方法,可以得到实例对象
Class classstu2 = Class.forName("com.weiwei.test1.Student");
Student student=(Student)classstu2.newInstance();
}
}
2.3 通过反射对象得到类的完整结构
Constructor<?>[ ] getConstructors() |
得到构造方法 |
Field[ ] getDeclaredFields() |
得到成员变量 |
Method[ ] getDeclaredMethods() |
得到成员方法 |
Class<?>[ ] getInterfaces() |
得到接口 |
Class<? super T> getSuperclass() |
得到父类 |
Package getPackage() |
得到包对象 |
int getModifiers() Modifier的toString(int mod) |
Java语言修饰符 转回字符串 |
String getName() |
得到类名称 |
【注意】上述方法中返回的数组,说明会有多个,需要遍历数组
例:得到下面类的信息
package com.weiwei.test2;
public class Student extends Person implements MyInter,MyInte{
private int stuid;
private String stuname;
public Student(){
}
public String getInfo()throws Exception{
return "";
}
}
测试类:
package com.weiwei.test2;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Main {
public static void main(String[] args) throws Exception{
//得到反射对象
Class stuclass = Class.forName("com.weiwei.test2.Student");
//得到包对象
Package package1 = stuclass.getPackage();
//得到包名称
String packname = package1.getName();
System.out.println("package"+"\t"+packname);
//得到类的访问限制修饰符
String modifier = Modifier.toString(stuclass.getModifiers());
//System.out.println(modifier);//public
//得到类的名称
//String classname1 = stuclass.getName();
//System.out.println(classname);//com.weiwei.test2.Student
//得到的类名是带有包名的,因此需要使用字符串操作类截取,新建一个方法
String classname = className(stuclass.getName());
//System.out.println(classname);//Student
//得到父类对象和父类名称
Class superclass = stuclass.getSuperclass();
String supername = className(superclass.getName());//Person
//得到接口对象和接口名称
Class interfaces[] = stuclass.getInterfaces();//得到数组
//System.out.println(interfaces.length);//2个
String interface1=className(interfaces[0].getName());
String interface2=className(interfaces[1].getName());
//输出类完整结构
System.out.println(modifier+" "+"class"+" "+classname+" "+"extends"
+" "+supername+" "+"implements"+" "+interface1+","+interface2+"{");
//得到成员变量
Field[] fields = stuclass.getDeclaredFields();
//遍历数组
for(Field field:fields){
String fieldmodifier = Modifier.toString(field.getModifiers());
String fieldtypeName = className(field.getType().getName());
String fieldname = field.getName();
System.out.println("\t"+fieldmodifier+" "+fieldtypeName+" "+fieldname+";");
}
//得到构造方法
Constructor[] constructors = stuclass.getConstructors();
Constructor constructor = constructors[0];
String conmodifier = Modifier.toString(constructor.getModifiers());
String conname = className(constructor.getName());
System.out.println("\t"+conmodifier+" "+conname+"()"+"{}");
//得到实例方法
Method[] methods = stuclass.getDeclaredMethods();
Method method = methods[0];
String methodmodifier = Modifier.toString(method.getModifiers());
String methodreturn = className(method.getReturnType().getName());
String methodname = method.getName();
String exname = className(method.getExceptionTypes()[0].getName());
System.out.println("\t"+methodmodifier+" "+methodreturn+" "+methodname+"()throws"+" "+exname+"{"+"\n\treturn xxx"+"\n\t}");
System.out.println("}");
}
/**
* 得到不带包名的类名称
*
*/
public static String className(String classname){
return classname.substring(classname.lastIndexOf(".")+1);
}
}
输出:
3.注解
注释---标注解释说明代码的含义用的文字
注解---标注解释说明功能的代码
1.@Override 判断方法重写是否正确
package com.weiwei.test2;
public class Son extends Person{
//重写父类的方法,很明显父类的方法是getinfo();
//显然目的是重写方法,但是写成了子类自己的方法,但不会报错
/*public void getInfo(){
System.out.println("重写父类的方法");
}
*/
//因此需要使用注解帮助自己,如果不一致会报错
@Override
public void getinfo(){
System.out.println("重写父类的方法");
}
}
2.@SuppressWarnings 抑制警告信息
有参数---产生警告的原因
位置:
- 当前代码的上面 ,只抑制当前代码上的警告信息
- 方法代码的上面 ,只抑制当前方法中的同类型的警告信息
- 类的上面 ,只抑制当前类中的同类型的警告信息
@SuppressWarnings({ "unused", "rawtypes" })
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings({ "unused", "rawtypes" })
public class Main {
//@SuppressWarnings({ "unused", "rawtypes" })
public static void main(String[] args) {
/*
* @SuppressWarnings("unused")
Person per=new Person();
@SuppressWarnings("rawtypes")
List list=new ArrayList();
*/
Person per=new Person();
List list=new ArrayList();
}
public void test(){
Person per=new Person();
List list=new ArrayList();
}
}
3. @Deprecated 标识变量/方法/类/接口,已过时。
已过时的元素尽量避免使用,因为有潜在的错误