10_Java高新_枚举-反射-注解-泛型

来源:互联网 发布:网络现金赌博游戏平台 编辑:程序博客网 时间:2024/04/28 02:30

------- android培训、java培训、.net培训、IOS培训 期待与您交流! -------

jdk1.5的新特性 可变参数

我们在写程序的过程中有可能要定义一个方法,
这个方法接收若干个参数,
但是参数的个数是不确定的。
比如,要定义一个求和的方法,为被传进来的若干值进行求和。

可变参数的特点:
1.只能出现在参数列表的最后。
2.可变参数用...表示。...位于变量类型和变量名之间,前面和后面有无空格都可以。
3.调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的方式访问可变参数。
以下为可变参数的测试示例:
package cn.itcast;public class VariableParameter {public static void main(String[] args) {System.out.println(add(1));System.out.println(add(1,2));System.out.println(add(1,2,3));}public static int add(int x,int... arr){int sum = x;for(int i:arr){sum+=i;}return sum;}}

overload  与 override的区别

overload叫重载,是同一个类中,同名不同参的方法之间的关系。
override叫重写,是子类和父类中相同方法之间的关系。


基本数据类型的自动装箱与拆箱

在jdk1.5以前,我们使用如下定义方式定义一个integer对象是不行的:
Integer iObj = 1;
我们必须这样定义:
Integer iObj = new Integer(1);

而1.5以后,这样定义就是可以的。
这叫自动装箱:自动把1这个数值封装成一个Integer对象,赋给iObj。

当我们执行如下语句的时候
System.out.println(iObj + 1);
是可以执行的,这里执行的就是自动拆箱技术。
把Integer类型的iObj自动拆箱成一个数值。

那么有人就会有这样的疑问:
Integer i1 = 1;
Integer i2 = 1;
如上两句中,i1和i2是否是同一个对象?

解答如下:
Integer i1 = 1;
Integer i2 = 1;
中,i1和i2是同一个对象。
但是在
Integer i1 = 133;
Integer i2 = 133;
中,i1和i2不是同一个对象。

这是为什么呢?
规则是这样的,当一个Integer类型的对象大小在一个字节之间,也就是-128~127之间时,
该数值会被放在一个池里面,等待下次有同样定义的时候,直接从池里找,节省了内存空间。
为什么只是一个字节呢?
因为这种小数值的对象可能使用频率会比较高,所以会将其放入池中待用。
像这种使用频率高且有不会对其值进行修改的的数据,如果每次被使用都在内存中新建一个对象,会很浪费内存空间。

当某种数据很小,但是又有很多地方需要这种数据,而且在使用的时候不会对其进行改变时,就没必要搞很多个,有一个就够了,大家都用这一个。
这叫享元设计模式(flyweight)

在什么情况写会用到享元设计模式呢?
在word中我们会经常输入英文字符,abcde...,如果每次输入一个字符都要在内存中创建一个对象的话,就会很浪费内存。
此时,使用享元设计模式,搞26个对象,分别对应26个字母就够了。
相同的字母每次出现的除了位置不同呢外,其他的都没有什么区别,
所以只要把显示的位置作为其某个方法的参数就可以让其在不同的地方进行显示了。

枚举的作用介绍

我们用枚举定义了一个新类型,
当以后创建这个类型的对象并为之赋值的时候,只能赋给枚举中规定的值。

枚举也是一个类,也可以定义构造方法。
但是定义构造方法的时候要注意,枚举中的元素列表必须在构造方法之前,不然Eclipse会报错。
总的来说就是,我们为枚举定义的其他信息,都必须位于枚举的元素列表之后。
而且,元素列表之后必须加分号(如果枚举中只有元素列表,那么元素列表之后可以不加分号)。

还有要注意的就是,枚举类的构造方法必须是私有的。

枚举类在被创建实例的时候,该枚举中的元素列表中的元素会被分别创建元素,
而构造方法就是用来创建元素的时候用的

具体理解请看如下代码和注释:
public enum WeekDay{SUN(1),MON,TUE,WED,THI,FRI,SAT;private WeekDay(){//在该枚举类被创建对象的时候,//除了SUN这个元素初始化时调用下面的有参构造方法外,//其余的都是调用的这个空参的构造方法}private WeekDay(int i){//SUN元素初始化时使用这个构造方法}}

交通灯枚举的例子

package cn.itcast;import java.util.Timer;public class TrafficLampEnum {public static void main(String[] args) {TrafficLamp tl = TrafficLamp.GREEN;//枚举的定义方式System.out.println(tl.next());}public enum TrafficLamp{RED(20){//每一个元素都是一个本枚举的实例对象,都要实现枚举中的抽象方法。public TrafficLamp next(){return GREEN;}},GREEN(21){public TrafficLamp next(){return YELLOW;}},YELLOW(3){public TrafficLamp next(){return RED;}};private int time;public abstract TrafficLamp next();private TrafficLamp(int time){this.time = time;}}}

如果枚举中只有一个成员,那么这个枚举就可以当作单例的一种实现方式。

也就是说,如果我们想写一个单例,可以使用只有一个元素的枚举来实现。

反射

大部分的框架都是要用到反射技术的。

和反射相关的类是Class,是各种类的一种字节码文件。
Java程序中的各个Java类属于同一类事物,描述这种事物的Java类就是Class。

得到字节码文件的方式有三种:
1.类名.class;
2.对象.getClass();
3.Class.forName("类名");

写程序时大多使用第三种方法。

得到字节码文件的三种方式展示以及一些方法的使用:

package cn.itcast;public class ReflectTest {public static void main(String args[]) throws ClassNotFoundException{String s = "abc";Class c1 = s.getClass();Class c2 = String.class;Class c3 = Class.forName("java.lang.String");System.out.println(c1 == c2);//trueSystem.out.println(c1 == c3);//true//上面两个输出语句都是true,说明不管用什么方式得到的字节码文件都是同一个String类的字节码文件。System.out.println(c1.isPrimitive());//是否是基本类型:falseSystem.out.println(int.class.isPrimitive());//是否是基本类型:trueSystem.out.println(int[].class.isPrimitive());//是否是基本类型:falseSystem.out.println(int[].class.isArray());//是否是数组:trueSystem.out.println(int.class == Integer.class);//两个类型的字节码是不一样的:falseSystem.out.println(int.class == Integer.TYPE);//TYPE代表的是Integer包装的 基本类型 的字节码,这了是true。}}

一个Class类代表一份字节码,一个Method代表这个字节码中的一个方法,一个Constructor代表一个字节码中的一个构造方法。

得到某个类中的所有的构造方法:

Constructor constructors[] = Class.forName("完整类名").getConstructors();

得到某个类中的某一个构造方法:

Constructor constructor = Class.forName("完整类名").getConstructor(对应参数类型.class);

有了构造方法,就可以用这个构造方法构造出一个实例对象。

那么如何构造出一个实例对象呢?

(创建的对象类型)constructor.newInstance(传入相应参数);//注意,一开始的强转是必要的。

上面两个红色的参数,必须要是同一种类型的参数。

Class.newInstance()方法

String obj = (String)Class.forName("java.lang.String").newInstance();

如上这句是可以执行成功的。

该方法内部先得到默认的构造方法,然后利用该构造方法创建实例对象。

也就是说我们如果在使用反射创建实例对象是,正好用到不带参数的构造方法时,可以这样来创建我们想要的实例对象。

而不用先得到Constructor再进行对象的创建。


如何获取成员变量

类中的成员变量也是用一个类来表示的。叫field类。


用字节码文件对象.getField("变量名");  

可以得到我们想要的成员变量。


Field field = xx.getClass().getField("xxx");

这里的field带包的是字节码文件中的变量,如何获得该变量在某个对象中的具体的值呢?

field.get("对象");

如果我们准备获取的变量是私有的,那么把getField换成getDeclaredField

然后在field.get("对象");前,先执行一句:field.setAccessable(true); 即可。


如何获得字节码文件中的成员方法

Method类代表的是某个类中的成员方法。

下面以获取String类中的charAt方法为例:

Method charAtMethod = String.class.getMethod("方法名",参数...);

拿到方法之后,如何使用呢?

charAtMethod.invoke("对象名","参数");//如果我们要调用一个静态的方法,那么这里的对象名传的是null。


专家模式:谁拥有这个数据,谁就是操作这个数据的专家,那么操作这个数据的方法就应该分配给谁。


数组的反射

这里要注意的就是:数据类型相同,且维数相同的数组的字节码文件是同一个。


ArrayList中可以存放相同的元素,HashSet不可以,如何理解记忆。

ArrayList是数组形式的集合,在每次讲对象的引用放入数组中时是按照顺序存放的,位置1,位置2...(数组中存放的不是对象本身而是对象的引用。),所以ArrayList允许元素重复。

HashSet每次放入元素前都要检查已有元素是不是包含要放入的元素,如果包含,那么就不放入。


内省

IntroSpector(内省)主要用于对javaBean进行操作。

那么什么是javaBean呢?

javaBean是一个特殊的Java类,其内部方法的名字符合某种规则。

那么是什么规则呢?

就是类中有些方法的方法名的开头是get或者set。

我们可以把一个javaBean当作一个普通的类来进行操作。

但是普通的Java类就不一定能把它当作JavaBean来操作了。

JavaBean应用是非常广泛的。

使用内省的方式操作javaBean。

PropertyDescriptor pd = new PropertyDescriptor("属性名","javaBean的字节码文件");//获取字节码文件中的属性

Method methodGetX = pd.getReadMethod();//得到属性对应的get方法

Object returnValue = methodGetX.invoke("对象名");//使用get方法

使用内省操作javaBean的set方法和上面操作get的方法类似。

Beanutils是专门用来操作javaBean的工具包

使用BeanUtils就需要在Eclipse中导入Beanutils专用的jar包。

但并不是导入BeanUtils包之后就可以使用里面的工具类了,

而是还需要导入BeanUtils用到的另一方的jar包:logging包。

BeanUtils以字符串的形式对javaBean的属性进行操作。

propertyUtils以javaBean属性本身的类型的形式对属性进行操作。


注解

很重要。
未来的开发模式,基本上都是基于注解(annotation)的。
如果我们想把自己原来开发的程序中的某个方法作废,因为它过时了。
这时我们不可以直接删掉,因为删掉后以前调用我的程序的程序就会运行不过去了。
此时我们可以再改方法上加上一个注释:@deprecated即可。

假如我们要覆盖父类的某一个方法,但是又怕自己覆盖的不准确,比如

父类方法:public void xxx(Object obj){}

我们写的方法:public void xxx(myClass mc){}

也就是我们在覆盖的时候,参数类型写错了,那么当程序调用我们写的类中的xxx方法的时候,

调用的就不是我们写的xxx方法,二是父类的xxx方法,因为我们覆盖没有成功。

那么如何避免出现这种情况呢?

可以使用注解:@Override

如果在加上这个注解之后,我们写的xxx方法,如果没有成功覆盖父类的xxx方法,那么Eclipse就会报错。

注解总结:注解就相当于一个标记,在程序中加了注解就等于为程序打上了某种标记,没加就等于没有打上某种标记。

打上标记之后,javac编译器、开发工具等程序可以用反射来了解我们的类以及各种元素上有没有什么标记,有什么标记,就去做相应的事。

标记可以加在包、类、字段、方法、方法的参数以及局部变量上。


我们要知道的是,我们写的注解其实是在调用相应的类。

我们为程序加上一个注解就是调用了一个类。

那么注解如何定义呢?

定义的关键字和接口是一样的,只是在interface前面加上了一个@:@interface。



当我们自己定义一个注解并在类上使用的时候,明明我们已经加了注解,可是使用

xx.class().isAnnotation("注解字节码文件");返回就是false。

这时候,可以再我们自己定义的注解上面加上一个注解:

@Retention(RetentionPolicy.RUNTIME)即可。此注解,表示让被注解的注解保留到运行时。

是在注解类上加的注解,成为元注解。

一个注解的生命有三个阶段:Java源文件-->.class文件-->字节码文件

如果把上面的RUNTIME换成SOURCE表示是Java源文件阶段,换成CLASS表示是.class阶段。

如果没有加元注解则默认生命周期是在.class阶段。


我们自己定义的注解默认是可以放到注解可以放置的任何地方的,

有一个元注解可以指定我们的注解的放置位置:

@Target(ElementType.METHOD)//被此元注解标注的注解只能加到方法上。

@Target({ElementType.METHOD,ElementType.TYPE)//既可以放到方法又可以放到类上。


注解的属性

什么事注解的属性,一个注解 就相当于一个胸牌,有了胸牌就说明你是某个单位的一员,

而想要知道你具体是这个单位的哪个部门的员工,就需要为胸牌(注解)加上一个属性来进行区分。

泛型

泛型的简单了解
在没有使用泛型的时候,只要是对象,不管是什么类型,都可以存储进同一个集合中。
使用泛型集合,可以将一个集合中的元素限定为某一个特定类型,集合中只能存储同一个类型的对象,这样更安全。
并且当从集合中获取对象时,编译器也可以知道这个对象的类型,程序员不需要对对象进行强制类型转换,这样更方便。

泛型中的?通配符
泛型中的参数类型是不考虑父子关系的。比如,
Collection<Integer>和Collection<Object>是没有任何等号关系的。
?表示任意类型
使用?通配符,可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,


但是不能调用与参数化有关的方法。
通配符?的扩展
我们可以通过关键字限制?通配符表示的类型上界和下界。
Collection<? extends Number>表示该集合中可以存放Number以及Number的子类。
Collection<? super Number>表示该集合中可以存放Number以及Number的父类。


HashMap中一个key以及该key对应的value合在一起可以组成一个Entry,Entry也是一个类。

只有引用类型才可以作为泛型方法的实际参数,而基本数据类型不行。
请看如下测试代码:
package cn.itcast;public class Test {public static void main(String[] args) {int[] i = {1,2,3,5,4};String[] s = {"a","b","c","e","d","f"};//swap(i,3,4);//报错。因为只有引用类型才可以作为泛型方法的实际参数,而基本数据类型不行。swap(s,3,4);for(String str:s){System.out.println(str);}}private static <T> void swap(T[] i, int j, int k) {T temp = i[j];i[j] = i[k];i[k] = temp;}}

在使用泛型的时候可以使用extends限定符,在定义泛型的时候,也是可以使用extends限定符的。


dao是data access Object (数据访问对象)的简写

什么叫crud

c:create 增

r:read 查

u:update 改

d:delete 删

也就是对数据库的增删改查操作。









------- android培训、java培训、.net培训、 IOS培训 期待与您交流! -------

0 0