Java高级应用之泛型与反射20170627
/******************************************************************************************************************/
一、泛型
不同的数据结构可以用同样的操作就是泛型
1.类使用泛型
class Person<T> {//要使用泛型的类加上类似与通配符的<T>,中间字符可以任意
//也可以传入多个类型<T,N>
private T age;//内部类型,使用T代替
public void setAge(T age) {//内部类型,使用T代替
this.age = age;
}
public T getAge() {//内部类型,使用T代替
return this.age;
}
}
public class Generics {
public static void main(String args[]) {
Person<String> p = new Person<String>();//创建对象的时候传入类型,如果是两个则<>里面放两个类型
p.setAge("3 years old");
//System.out.println(p.getAge());
printInfo(p);
Person<Integer> p2 = new Person<Integer>();//<>内只能用类,所以不能用基础数据类型int要用Integer类代替
p2.setAge(3);
//System.out.println(p2.getAge());
printInfo(p2);
Person<?> p3;
p3 = p;//通用引用p3赋值
//p3.setAge("4 years");//不能设置(类型冲突)
p3.getAge();//但可以获取
}
public static void printInfo(Person<?> p) {//Person<?>是通配符,表示传进来可以是String类也可以是Integer类
System.out.println(p.getAge());
}
}
2.方法使用泛型
1)定义
public static <T> void printInfo2(Person<T> p) {//定义格式返回值前面,参数里都要有相应的<T>
System.out.println(p.getAge());
}
2)调用
printInfo2(p);//p为具体的对象Person<String> p = new Person<String>();
printInfo2(p2);
printInfo2(p3);
3.子类使用泛型(泛型的继承)
1)定义
class Student<T> extends Person<T> {//子类继续使用泛型
}
class Student2 extends Person<String> {//子类不再使用泛型
//子类确定类型为String,所以前面也就不需要加<T>,同时对应父类的类型也已被确定
}
2)调用
Student<Integer> s = new Student<Integer>();//创建子类对象,传入类型
s.setAge(10);//调用父类的方法
printInfo(s);//向上转换
Student2 s2 = new Student2();//已经确定类型,不需传入
s2.setAge("11 years");//对应父类的类型已被确定,调用父类方法直接传入String
printInfo(s2);
4.接口使用泛型(接口:特殊的父类)
interface Person<T> {
public void setAge(T age);
public T getAge();
}
class Student<T> implements Person<T> {//子类继续使用泛型
T age;
public void setAge(T age){
this.age = age;
}
public T getAge() {
return this.age;
}
}
class Student2 implements Person<String> {//指定对应接口的泛型类型
String age;///已经确定了类型,直接使用
public void setAge(String age){
this.age = age;
}
public String getAge() {
return this.age;
}
}
public static void main(String args[]) {
Student<Integer> s = new Student<Integer>();//创建子类对象,传入类型
s.setAge(10);
printInfo(s);//向上转换(接口:特殊的父类),子类里实现了方法,同时父类也就是接口没有实现对应的方法,所以里面调用的是子类的方法
Student2 s2 = new Student2();//已经确定类型,不需传入
s2.setAge("11 years");
printInfo(s2);
}
public static void printInfo(Person<?> p) {
System.out.println(p.getAge());
}
5.受限泛型
声明泛型的时候可以指定泛型的上限和下限
1)泛型的上限:<T extends Number> T只能是Number类或其子类
/*T只能是Number类或其子类Integer, Float 等*/
class Student<T extends Number> implements Person<T> {
T age;
public void setAge(T age)
{
this.age = age;
}
public T getAge() {
return this.age;
}
}
2)泛型的下限:<? super String> T只能是String类或其父类
super只能使用通配符,不能直接在名字里使用(即只能在使用这个泛型的时候再指定),所以还是:
class Student<T> implements Person<T> {
T age;
public void setAge(T age)
{
this.age = age;
}
public T getAge() {
return this.age;
}
}
//使用的时候指定下限(用通配符?指定下限)
public static void printInfo(Person<? super String> p) {//传进来 只能是String类或其父类
System.out.println(p.getAge());
}
调用:
Student<String> s = new Student<String>();
s.setAge("10");
printInfo(s);
/******************************************************************************************************************/
二、反射
正常步骤我们是import"包.类"然后通过new实例化最后得到实例化对象
那么能否反过来呢
从实例化对象得到getClass方法最后得到完整的"包.类"名称
这个反过来的操作(根据实例化对象得到完整的"包.类"名称)就是所谓的反射操作(当然反射的作用不仅仅是得到完整的"包.类"名称)
注意:在反射操作中,一切的操作都使用Object完成,类,数组的引用都可以使用object进行接收
1.class对象和"类的实例化对象"
Person p=new Person();
System.out.println(p.getClass().getName());//打印"包.类"名称
JVM会加载*.Class文件(java写的类)到内存里,也就是会在内存里创建一个class object用来描述这个类,包括类的包,类名称,构造方法,方法,属性,这样就可以使用这个class object来实例化对象(在内存里对于一个class只有一个class object,这个class object是用来描述类本身的,我们可以使用这个class object来创建实例化对象)可以有三种方法获得一个类的class object:
2.获得class
1).Class<?> c=Class.forName("包.类");
Class<?> c1 = null;
try {
c1 = Class.forName("a.b.c.d.Person");
} catch (ClassNotFoundException e) {
System.out.println(e);
}
System.out.println(c1.getName());
2).Class<?> c=new X().getClass();
Person p = new Person();
Class<?> c2 = p.getClass();
System.out.println(c2.getName());
3).Class<?> c=X.class
Class<?> c3 = Person.class;
System.out.println(c3.getName());
3.对于数组或者其他数据类型,也有对应的类,对应的class object
int arr[] = {1,2,3};
int arr2[] = {1,2,3,4};
int arr3[][] = {{1,2,3,4},{1}};
Class<?> c4 = arr.getClass();
Class<?> c5 = arr2.getClass();
Class<?> c6 = arr3.getClass();
Class<?> c7 = int.class;
System.out.println(c4.getName());
System.out.println(c5.getName());
System.out.println(c6.getName());
System.out.println(c7.getName());//基本的数据类型也是一个类,里面也有class
System.out.println((c4 == c5));//同样的数组类型是一样的class
System.out.println((c4 != c6));//二维数组和一维数组不一样所以不一样的class
4.使用反射来获取类的实例化对象(类的属性与方法),取代import a.b.c.d.Person;(的形式)
public static void main(String args[]) throws Exception {//Exception 是其他的异常父类,所以可以这样代替InstantiationException等其他异常
Class<?> c = null;
try {
c = Class.forName("a.b.c.d.Person");//使用名字来获得这个Person的class object
} catch (ClassNotFoundException e) {
System.out.println(e);
}
Object p = null;//然后创建它的实例化对象(Object是所有类的父类,所以可以这么写)
try {
p = c.newInstance();//然后创建它的实例化对象(Object是所有类的父类,所以可以这么写(可以向上转换)),实际是调用了那个类的无参构造方法
} catch (InstantiationException e) {
System.out.println(e);
}
//调用有参构造方法的实例化
Constructor<?> con = c.getConstructor(String.class);//获得参数是String的构造方法 的class
Object p2 = con.newInstance("123");//然后创建它的实例化对象,有参数
5.获得并调用类的方法:
Method set = c.getMethod("setName", String.class);//传入方法名称(该方法在定义的地方要有public权限),参数类型
set.invoke(p2, "123");//调用实例化对象中的方法,要设置的实例化对象,然后才是传入的值
set.invoke(p, "abc");
//对于静态方法, invoke的第1个参数可以写为null
Method get = c.getMethod("getName");//没有传入参数
System.out.println(get.invoke(p));
System.out.println(get.invoke(p2));
6.读取或设置类的属性
1).最好是用上面的方式,通过方法来访问类的属性
2).也可以直接获取属性:
(1)Field f = c.getField(String name); // 获得公共属性, 此方法先搜本类, 再搜它实现的接口,最后在父类中搜索
(2)Field name = c.getDeclaredField("name");//可以获得类里面所有属性(包括private,public等)中名为name的属性
name.setAccessible(true);//设置为可访问,如果要访问的属性为public可以不要这句话,其实设置为可访问也就破坏了类的封装性,所以一般不使用这种方法,而是去调用那个类的设置获取方法
name.set(p, "www");//设置某个实例化对象中的name属性
name.set(p2, "123");//设置p2这个实例化对象中的name属性
System.out.println(name.get(p));//获得某个对象的name属性
System.out.println(name.get(p2));
7.使用反射的好处
增加程序灵活性,通过类的名称(放在文件里或者通过参数传递,这就不用在代码中写死,传入什么就可以实例化什么),然后就可以实例化出不同的对象
Java高级应用之泛型与反射20170627的更多相关文章
- Java高级应用之泛型与反射
/*************************************************************************************************** ...
- Java高级特性之泛型
首先我们先提出两个问题: 什么是泛型? 为什么要使用泛型?我们先来看看第一个问题什么是泛型.如果你对Java三大特性中的多态性理解的比较透彻的话,泛型就比较好理解了.多态性表示一个对象具备多种状态.比 ...
- Java高级篇(四)——反射
之前写到了设计模式的代理模式,因为下一篇动态代理等内容需要用到反射的知识,所以在之前Java篇的基础上再写一篇有关反射的内容,还是以实际的程序为主,了解反射是做什么的.应该怎么用. 一.什么是反射 反 ...
- java高级——反射
慕课网<反射——Java高级开发必须懂的>听课笔记 一.class类的使用 class ClassDemo { public static void main(String[] args) ...
- 从一知半解到揭晓Java高级语法—泛型
目录 前言 探讨 泛型解决了什么问题? 扩展 引入泛型 什么是泛型? 泛型类 泛型接口 泛型方法 类型擦除 擦除的问题 边界 通配符 上界通配符 下界通配符 通配符和向上转型 泛型约束 实践总结 泛型 ...
- Java高级语法之反射
Java高级语法之反射 什么是反射 java.lang包提供java语言程序设计的基础类,在lang包下存在一个子包:reflect,与反射相关的APIs均在此处: 官方对reflect包的介绍如下: ...
- 应用Java泛型和反射导出CSV文件
项目中有需求要把数据导出为CSV文件,因为不同的类有不同的属性,为了代码简单,应用Java的泛型和反射,写了一个函数,完成导出功能. public <T> void saveFile(Li ...
- 反射---Java高级开发必须懂的
理解反射对学习Java框架有很大的帮助,如Spring框架的核心就是使用Java反射实现的,而且对做一些Java底层的操作会很有帮助. 一.Class类的使用 1.万事万物皆 ...
- Java高级特性之反射学习总结
老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用 ...
随机推荐
- 韦大仙--LoadRunner压力测试:详细操作流程
一. 录制脚本 1.安装完毕后,创建脚本: 点击OK之后,会弹出网址,之后创建Action,每进一个页面添加一个Action,录制结束后,终止录制. 二. 修改脚本 1.脚本参数化 将登录的用户名密码 ...
- 【UGUI】 (一)------- 放大镜
在许多游戏或应用中,我们常常看到放大镜的身影,而在Unity里面,制作一个简易的放大镜是非常简单的. 一. 创建一个3DObject 创建一个Cube或者 Cylinder,这里为了更像放大镜一 ...
- CMDBuild2.4.3安装配置
参考文档: 官网:http://www.cmdbuild.org/en 参考:http://blog.csdn.net/shawn210/article/details/70230248 本文涉及CM ...
- shell基础 -- 入门篇
shell 英文含义是“壳”,这是相对于内核来说的,shell 也确实就像是内核的壳,通常来说,所有对内核的访问都要经由 shell .同时,shell 还是一门功能强大的编程语言.shell 是 L ...
- Debian 9 + Windows 10 双系统安装体验
很久之前就想在自己的电脑上也装个 Debian 玩玩了,最近正好有时间折腾,就踩了踩坑在笔记本上装了玩玩~ UEFI + GPT 解决启动相关的麻烦配置 如果在支持 UEFI 的电脑上安装 Debia ...
- linux源码学习-for_each_cpu
刚开始读linux源码,第一眼就看到了这个很有意思的函数族,周末好好研究一下 3.13 这个组都是宏定义for循环,分析的时候注意到cpumask_next(),它在一个文件中定义了两次,还不是重载, ...
- Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
1. 摘要 训练深层的神经网络非常困难,因为在训练的过程中,随着前面层数参数的改变,每层输入的分布也会随之改变.这需要我们设置较小的学习率并且谨慎地对参数进行初始化,因此训练过程比较缓慢. 作者将这种 ...
- 华为笔试——C++特定位数比较
题目:特定位数比较 题目介绍:输入两行数据,第一行为 m 个正整数,以空格隔开:第二行为正整数 n ,且 n<= m:要求对第一行的数字的后三位大小进行排序,输出排行 n 的数字,其中,若不满三 ...
- OOP 1.4 内联函数和重载函数函数参数缺省值
1.内联函数 存在的背景:函数调用存在开销(调用时候参数压栈,返回地址压栈:返回时从栈取出返回地址,跳转到返回地址.总共需要几条指令的开销).如果函数指令较少,调用多次,函数调用的开销占比大. 内联函 ...
- 第5题 查找字符串中的最长回文字符串---Manacher算法
转载:https://www.felix021.com/blog/read.php?2040 首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一 ...