黑马程序员---Java高新技术学习笔记(前篇)

来源:互联网 发布:淘宝店上传完宝贝 编辑:程序博客网 时间:2024/05/21 04:39

------------Android培训Java培训期待与你交流------------

1.枚举

枚举是JDK1.5出现的新特性,其实就是一个特殊的类,其中也可以定义构造方法,成员变量,普通方法和抽象方法。枚举元素必须位于方法体中最开始的部分,枚举元素列表需要用分号和其他成员分隔。把枚举重的成员方法或变量等放在枚举元素的前面,编译器会编译失败。

用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。首先要有私有的构造方法,每个元素分别都是一个公有的静态成员变量表示,可以有若干公有方法或抽象方法。这是带构造方法的枚举, 构造方法必须定义成私有的,枚举元素MON和MON()的效果一样,都是调用默认的构造方法。如果希望元素调用带有参数的构造函数初始化,可以在元素名后面加上参数。带方法的枚举可以通过定义枚举TrafficLamp这个例子来验证,实现普通的next方法, 实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。增加上表示时间的构造方法。具体实现代码如下:

本人比较懒,把两个例子写到一个里去了~~

public class EnumTest{public static void main(String[] args){/*对应WeekDay01中的注释部分WeekDay01 weekDay = WeekDay01.MON;System.out.println(weekDay.nextDay());*//*WeekDay weekDay02 = WeekDay.FRI;System.out.println(weekDay02);System.out.println(weekDay02.name());System.out.println(weekDay02.ordinal());//所在位置的indexSystem.out.println(weekDay02.getClass());System.out.println(WeekDay.valueOf("SUN").toString());System.out.println(WeekDay.values().length);*/     //      //     //}       //    //\\//public enum WeekDay{//均为静态变量SUN,MON(1),TUE(1),WED,THU(1),FRI,SAT;//元素类表必须置于所有方法之上,//如果列表后边有内容最后需要加分号,如果没有可不加。//加括号是为了调用有参数的构造方法private WeekDay()//只能是私有类型的构造函数{System.out.println("first");}private WeekDay(int day){System.out.println("second");}}public enum TrafficLights{//new一个子类的实例对象<RED>,并且调用父类(TrafficLights)有参数的//构造方法private TrafficLights(int time)<(30)>RED(30){public TrafficLights nextLamp(){return GREEN;}} , GREEN(45){public TrafficLights nextLamp(){return YELLOW;}} , YELLOW(5){public TrafficLights nextLamp(){return RED;}};public abstract TrafficLights nextLamp(); private int time;private TrafficLights(int time){this.time = time;}}}
public abstract class WeekDay01{private WeekDay01(){}//私有的构造方法public final static WeekDay01 SUN = new WeekDay01(){//匿名内部类public WeekDay01 nextDay()//覆盖父类的方法{return MON;}};public final static WeekDay01 MON = new WeekDay01(){//匿名内部类public WeekDay01 nextDay(){return SUN;}};/*对应EnumTest中注释部分public final static WeekDay TUE = new WeekDay();public final static WeekDay WED = new WeekDay();public final static WeekDay THE = new WeekDay();public final static WeekDay FRI = new WeekDay();public final static WeekDay SAT = new WeekDay();public WeekDay nextDay(){if(this == SUN){return MON;}else{return SUN;}}*/public abstract WeekDay01 nextDay();//因为是抽象方法,所以其所在的类也必需要变成是抽象的public String toString(){return this==SUN?"SUN":"MON";}}

2.反射

反射就是把Java类中的各种成分映射成相应的java类。
例如:一个java类用一个Class类的对象来表示,一个类的组成部分:成员变量,方法,构造方法,包等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等
信息,这些信息就是用相应类的实例对象来表示,他们是Field,Method,Constructor,Package等。

Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有着不同的属性值。java程序中的各个java类,它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class,要注意与小写class关键字的区别。

字节码:当在源程序中用到了Person这个类的时候,首先要从硬盘上把这个类的二进制代码加载到内存中,才能去创建一个个的对象,当程序中用到了多个类时候,内存中就会有多个相应的字节码,每一个字节码就是Class的实例对象总之,只要是在源程序中出现的类型,都有各自的Class实例对象。 

Person p1 = new Person();
Person p2 = new Person();

Class cls1 = Date.class(内存中)Date类字节码1;
Class cls2 = Person.calss(内存中)Person类字节码2;
 
获取字节码的方式(3种)
1.对象.getClass() 比如p1.getClass() / new Date().getClass()
2.Class.forName("java.lang.String")-->静态方法
<两种情况>1.此类的字节码已经加载到内存中了,用时可直接返回
2.此类的字节码还没有加载到内存中,便用类加载器将其加载到内存中缓存起来
 3.类名.class 比如System.class

有关以上内容的一些具体实现代码:

import java.lang.reflect.*;//import java.lang.reflect.Field;//import java.lang.reflect.Method;public class ReflectTest{public static void main(String[] args) throws Exception{String str1 = "abc";Class cls1 = str1.getClass();Class cls2 = String.class;Class cls3 = Class.forName("java.lang.String");System.out.println(cls1==cls2);System.out.println(cls2==cls3);System.out.println(cls1==cls3);    //System.out.println(cls1.toString());System.out.println(cls1.isPrimitive());//判断是否是基本类型的字节码System.out.println(int.class.isPrimitive());//int型为基本类型的字节码System.out.println(int.class==Integer.class);//int和Integer的类型不同System.out.println(int.class==Integer.TYPE);System.out.println(int[].class.isPrimitive());//数组不是原始类型System.out.println(int[].class.isArray());/*================================华丽的分割线====================================*///new String(new StringBuffer("abc"));//新new一个对象,调用了StringBuffer构造方法//用反射的方式实现形同的效果Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//Constructor类型的对象,此句中的StringBuffer表示选择哪种构造方法//constructor1此时只是一堆存在内存中没有实例化的二进制代码//(String类中StringBuffer构造方法的字节码),下一条语句才会进行实例化String str = (String)constructor1.newInstance(new StringBuffer("abc"));//此句中的StringBuffer表示用此构造方法是需要传一个StringBuffer进去/* * 泛型的应用省去了类型转换之苦Constructor<String> cons = String.class.getConstructor(StringBuffer.class);String strr = cons.newInstance(new StringBuffer("abcd"));*/System.out.println("str:"+str);System.out.println(str.charAt(1));Object obj = constructor1.newInstance(new StringBuffer("abc"));System.out.println("obj:"+obj);System.out.println(obj.toString());/*================================华丽的分割线====================================*//*//成员变量的反射 * Field类代表某一个类中的一个成员变量 * 以下代码对应ReflectPoint.java文件 */ReflectPoint pt1 = new ReflectPoint(3,5);Field fieldY = pt1.getClass().getField("y");//只用于可见变量//此时fieldY只是代表一个实例化的变量,不代表一个具体的值//也就是说他不是对象身上的变量,而是类上的变量,需要实例化才有值System.out.println(fieldY.get(pt1));//需要用get方法来获取指定变量的值Field fieldX = pt1.getClass().getDeclaredField("x");//可见变量和非可见变量均可fieldX.setAccessible(true);//暴力反射System.out.println(fieldX.get(pt1));/*================================华丽的分割线====================================*///成员变量的反射changeStringValue(pt1);System.out.println("pt1:"+pt1);/*================================华丽的分割线====================================*///成员方法的反射//利用反射的方法调用字符串中的字符Method methodCharAt = String.class.getMethod("charAt" , int.class);//调用Str1.charAt(1)中的字符bSystem.out.println(methodCharAt.invoke(str1 , 1));System.out.println(methodCharAt.invoke(null , 1));//若第一个参数为null,说明该方法为静态//按照JDK 1.4 version的方法调用str1中的字符c//Object[]{2}) object类型的数组,里面只有一个Integer对象2,数组长度为1System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//JDK 1.4 version/*================================华丽的分割线====================================*///用反射方式执行某个类中的main方法,为什么?//CodeSegment/*String startingClassName = args[0];Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);mainMethod.invoke(null, new String[]{"111","222","333"});调用此段代码是会出现参数个数不对的异常,原因是new String[]{"111","222","333"}在JDK1.5+中为了兼容JDK1.4,JVM在接受此数组是默认为object的数组,进行拆包从而不会当成一个参数,此数组会被打开数组中的元素分别作为一个参数,从而有三个参数解决办法:1.再次打包new Object[]{new String[]{"111","222","333"}}即使String数组被打开,仍然是一个Object数组2.(Object)new String[]{"111","222","333"}对编译器指明此参数为一个对象,而不是数组,不需要进行拆包*///main方法是静态方法,不需要传递对象//目标:根据用户提供的类名,去执行该类中的main方法TestArguments.main(new String[]{"111","222","333"});/*================================华丽的分割线====================================*/}private static void changeStringValue(Object obj) throws Exception{//将对象中所有的String类型的变量进行扫描Field[] fields = obj.getClass().getFields();//先得到obj所属的那份字节码,再得到所属的字段,对字段进行迭代for(Field field : fields){//if(field.getType().equals(String.class))不建议使用//因为只需要得到object中String类型的字段,所以将字段中的所有元素的类型通过//field.getType()方法利用迭代方式逐次//和String类型的字节码进行比较,相同的保留,不同的舍去if(field.getType() == String.class)//字节码要用等号比较,专业{String oldValue = (String)field.get(obj);//得到字段中String类型元素String newValue = oldValue.replace('b', 'a');//将字符串中目标字符进行替换field.set(obj, newValue);//将生成的新字符串赋值给obj}}}}class TestArguments{public static void main(String[] args){for(String arg : args){System.out.println(arg);}}}
------------Android培训Java培训期待与你交流------------







 

原创粉丝点击