黑马程序员——19Java高新技术1


------------ android培训 java培训 、期待与您交流!------------  
 
 
 1, JDK 1.5 新特性:1 )静态导入。 importstatic java.lang.Math
                                
2 )可变参数。 VariableParameter.java 。必须放在参数列表末尾。实际内部封装成数组。
                                
3 )增强 for 循环。遍历的集合为数组或实现 Iterable 接口。
                                
4 )基本数据类型自动拆箱与装箱。
                                
5 )享元设计模式。
                                
6 )枚举。
                                
7 )注解。
                                8)Type接口。
                                9
)泛型。
 2 ,MyEclipse的使用技巧。
     1)MyEclipse与Eclipse之间的关系,MyEclipse是Eclipse的一个插件,后来MyEclipse把这两个东西打包起来,直接下
载,Eclipse是用java开发的,启动MyEclipse,查看任务管理器可以看到javaw.exe运行。
       2) IDE 开发工具都支持使用工程化方式管理一个项目的程序开发过程,一般来说一个相对独立的项目就是一个工程,一个项目中涉及的多个 java 文件,资源文件等用一个工程进行管理。
       3)  一个 workspace 可以包含多个 project ,一个 workspace 保留了 eclipse 的一套环境选项的配置,例如,所使用的 javac java 命令等,细节请查看 window->preferences 。如果要为 eclispe 再配置一套环境选项,可以再创建一个 workspace
 
      4)一个Perspective(透视图)代表了若干个view的集合,如何显示各种view。
       5) 设置单个工程的 javac java ,选择工程->右键 ->properties。设置整个工作间的javac和java,Window->Properties->java进行设置。高版本的可以运行低版本编译的程序。
       6) 快捷键使用技巧:配置Window->Properties-> General->keys ,设置 alt+/ 键进行内容提示(Content Assist)时,要注意解除 alt+/ 键原来的绑定关系,直接输入 alt+/ 就可以找到它的绑定关系,删除绑定关系时也可以使用 remove binding 这个按钮 。代码模板的设置位置: Window->Properties-> java->editor->Templates。
       7)调试程序,设置断点->Debug As ->选中变量->右键Watch->走一步。即可查看某一变量的值的变化。
       8)在工作间导入新的工程,复制到工程到工作间->File->Import->Existing Projects into Workspace->选择工程->Finish。此时JDK环境有可能不一样,需要重新配置。右键->Build Path->Configure Build Path->Libraries->删掉原来的库->AddExternal JARs,若是jar包已拷入工程里,用Add JARs添加,若增加库用Add Library->User Library。

3,静态导入。
    import语句可以导入一个类或某个包中的所有类。
    import static语句导入一个类中的某个静态方法或所有的静态方法。
    
import static java.lang.Math.*;
    
import com.itheima.day2.AnnotationTest;
    public class StaticImport {
        public static void main(String[] args){
            System.out.println(abs(6-7));
            System.out.println(max(2, 5));
        }
    }
 
4,可变参数。
        overload和override的区别:重载要求函数名相同,参数的顺序,类型或者个数不同,与返回值、修饰符没有关系。而重写要求函数名,参数均与父类相同,返回值可以不同,但必须是父类的子类型。而且子类访问修饰符大于父类,子类的异常小于父类,静态方法和final方法不能被重写。
         可变参数出来之前,只能用overload来重载。
public class VariableParameter {
        public static void main(String[] args) {
                System.out.println(add(1,3,5,6,78));
                System.out.println(add(1,3));
        }
        //可变参数。必须放在参数列表末尾。内部实际封装被成数组。
        public static int add(int x,int...args){
                int sum=x;
                //增强for循环(JDK1.5新特性),查看langspec(java官方提供的语言规范)。目标集合必须实现Iterable接口
                for(int arg:args){
                        sum+=arg;
                }
                return sum;
        }
}
 
5, 自动拆箱装箱。
public class AutoBox {
        public static void main(String[] args) {  
                //自动装箱
                Integer iObj=3;
                //自动拆箱 
                System.out.println(iObj+12);
                //一个字节,值-128~127内。把这个对象在堆内存的常量池中缓存起来,这些对象具有小而多的特点,这些对象具有相同的属性,称为这些对象的内部状态。这时这个对象只创建一次,别的地方引用即可, 即享元设计模式。flyweight
再深入理解享元、枚举,实际都是一种单例模式。 
                Integer i1=13;
                Integer i2=13;
                System.out.println(i1==i2);    //true,一个对象
 
                Integer i3=137;
                Integer i4=137;
                System.out.println(i3==i4);    //false ,两个不同的对象

                 Integer i5=Integer.valueOf(123);
                Integer i6=Integer.valueOf(123);
                System.out.println(i3==i4);    //true,    一个对象

                
Integer i7=new Integer(123);
                Integer i8=new Integer(123);
                System.out.println(i7==i8);      //false ,   两个不同的对象
        }
}
 
6,枚举。
    1)用普通的java类来模拟一个枚举类。
public abstract class WeekDay1 {
        private WeekDay1(){}     //构造函数私有化,不允许外部创建对象
        public abstract WeekDay1 nextDay();      //定义一个抽象的方法
        public final static WeekDay1 SUN=new WeekDay1(){       //重写nextDay方法
                public WeekDay1 nextDay() {
                        return MON;
                }
        };
        public final static WeekDay1 MON=new WeekDay1(){
                public WeekDay1 nextDay() {
                        return TUES;
                }
        };
        //重写toString()方法
        public String toString(){
                if(this==SUN){
                        return "SUN";
                }else
                        return "MON";
                }
        }
}
2)//测试枚举。 
public class EnumTest {
        public static void main(String[] args) {
                //测试我们模拟的枚举类。 

                WeekDay1 weekDay=WeekDay1.MON;
                System.out.println(weekDay.nextDay().toString());
/*
* 新来的程序员如何知道weekDay赋7还是0?且编译时不报错
* 这就是个问题?解决:枚举。
定义一个WeekDay weekDay=0;  以后用WeekDay这个类型定义的值只能是提前规定好的值, 否则编译时就报错,这就是枚举。
*/
                //测试我们利用API做的枚举。 
                WeekDay weekDay2=WeekDay.FRI;
                System.out.println(weekDay2);       //枚举自动帮我们复写了toString方法。
                System.out.println(weekDay2.name());
                System.out.println(weekDay2.ordinal());       //枚举对象排第几。
                System.out.println(weekDay2.getClass());       //得到该对象的字节码对象。
                //枚举提供的静态方法。 
                System.out.println( WeekDay.valueOf("SUN").toString());       //把字符串“SUN”变成对象。
                System.out.println( WeekDay.values().length);     //得到枚举类中的对象数组
                System.out.println(TrafficLamp.RED.nextLamp());
        }
        3) //利用API定义一个带方法和带构造方法的枚举类,此处作为内部类。
        public enum WeekDay{
                //枚举元素必须位于所有成员之前,若之后有成分,必须在元素后加分号
                SUN,MON(3),TUES,WED,THUR,FRI,SAT;
                //定义一个不带参数的构造方法。枚举的构造方法必须是私有的。
                private WeekDay(){System.out.println("first");}
                //定义一个带参数的构造方法。 
                private WeekDay(int day){System.out.println("second");}
        }
        4) //定义一个交通灯的枚举类。这个枚举带有抽象方法。
        public enum TrafficLamp{
                RED(30){
                        //子类复写父类的抽象方法。 
                        public TrafficLamp nextLamp(){
                                return GREEN;
                        }
                },
                GREEN(45){
                        public TrafficLamp nextLamp(){
                                return YELLOW;
                        }
                },
                YELLOW(5){
                        public TrafficLamp nextLamp(){
                                return RED;
                        }
                };
                 //定义一个抽象方法。
                 public abstract TrafficLamp nextLamp();
                private int time;
                private TrafficLamp(int time){
                        this.time=time;
                }
        }
}
注意 : 当枚举只有一个成员时,可以作为一种单例的实现方式。

7,反射。JDK1.2的特性。
    Class类,它的对象代表内存中的一份字节码。
    反射就是把 java 类中的各种成分映射成相应的 java 类。
例如,一个
java 类中用一个 Class 类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的 java 类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示 java 类中的 Class 类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应的类的实例对象来表示,他们是 Field Method Contructor Package 等等。
 
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。 得到字节码对应的实例对象的 3 种方法:
                 
1) 类名 .class ,例如: System.class
                 
2) 对象 .getClass() ,例如: new Date().getClass()
                 
3)C lass.forName(“ 类名 ”) ,例如: Class.forName(“java.util.Date”)
//第三种方式,把类名作为一个参数传进来。写源程序时还不知道类的名字,它的名字是在运行时作为参数传进来的,所以反射通常用这种方式。
 
九个预定义的 Class 对象:八个基本类型 +void
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.util.Arrays;
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);        //true
                System.out.println(cls2==cls3);        //true, 可知在内存中只有一份字节码。
                //Class类的一些基本方法。
                System.out.println(cls1.isPrimitive());    //false是否是原子类型。
                System.out.println(int.class.isPrimitive());    //true
                System.out.println(int.class==Integer.class);    //false,两份字节码
                System.out.println(int.class.equals(Integer.class));     //没有复写Object的equals,代表比较Class对象的引用。
                System.out.println(int.class==Integer.TYPE);    //true, 包装类型.TYPE代表他所包装的基本类型的字节码。
                System.out.println(int[].class.isPrimitive() );    //false,数组不是原子类型
                 System.out.println(int[].class.isArray());      //true,判断Class对象是否是数组字节码
                //总之,在源程序中出现的类型,都有各自的Class实例对象。 例如:int[ ],void
        
                1)//将Class对象中的构造方法反射到Constructor对象
                //用反射来实现new String(new StringBuffer("abc")); 
                //只接受参数类型是StringBuffer的一个构造方法。
                Constructor constructor1=String.class.getConstructor(StringBuffer.class);
                String str2=(String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));
                System.out.println(str2.charAt(2));
                //Class提供的newInstance() 直接可以new对象,但只可new一个无参的对象。查看API源代码可知它内部实际就是上述反射操作,但它把这个空参数的构造方法缓存起来,以便下次直接使用,这也说明的反射比较耗费资源。

                 2)//将Class对象中的成员变量反射到Field对象
                ReflectPoint pt1=new ReflectPoint(3,5);
                //fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值。
                Field fieldY=pt1.getClass().getField("y");
                Field fieldX=pt1.getClass().getDeclaredField("x");     //得到私有的x变量。
                System.out.println(fieldY.get(pt1));
                fieldX.setAccessible(true);    ·//暴力反射私有变量。
                System.out.println(fieldX.get(pt1));
                //调用自定义的方法改变String变量的值
                changeStringValue(pt1);
                //反射点已复写toString方法,可以直接打印对象了。 
                System.out.println(pt1);

                 3)//将Class对象中的方法反射到Method对象
                //用反射来实现这个操作str1.charAt(1);
                Method methodCharAt = String.class.getMethod("charAt", int.class);
                System.out.println(methodCharAt.invoke(str1, 1));
                //第一个参数为null,则methodCharAt肯定是一个静态方法的对象。
                //System.out.println(methodCharAt.invoke(null, 1));
                //按JDK1.4的语法调用,没有可变参数,用Object数组。 
                System.out.println(methodCharAt.invoke(str1, new Object[]{Integer.valueOf(2) /*2自动装箱*/}));
                //自己写程序去调用人家的main方法。
                //用反射实现TestArguments.main(new String[]{"zhangsan","lisi","wangwu"});
                //为什么要用反射? 提前不知类的名字,用参数传递的方式把类名传进来, 执行时,传进来哪个类执行哪个类。
                String startClassName = args[0];
                Method main = Class.forName(startClassName).getMethod("main", String[].class);
                 main.invoke(null, new String[]{"111","222","333"});    //编译报错 java.lang.ArrayIndexOutOfBoundsException 自动拆包一次,变成3个参数
                 //编译器为兼容1.4版本,对字符串数组自动拆包一次。
                解决方法1:
                 main.invoke(null, new Object[]{new String[]{"111","222","333"}});
                解决方法2    
                 main.invoke(null, (Object)new String[]{"111","222","333"});
                 
                4)//数组的反射。 
                int[] a1=new int[]{1,2,3};
                int[] a2=new int[4];
                int[][] a3=new int[2][3];
                String[] a4=new String[]{"a","b","c"};
                System.out.println(a1.getClass() == a2.getClass());     //true,具有相同维度且具有相同的类型。
                 System.out.println(a1.getClass() == a4.getClass());    //false
                 System.out.println(a1.getClass() == a3.getClass());    //false
                System.out.println(a1.getClass().getSuperclass().getName());    //java.lang.Object
                System.out.println(a4.getClass().getSuperclass().getName());    //java.lang.Object
                Object obj1 = a1;
                Object obj2 = a4;
                 //Object[] obj3 = a1;    int类型不是Object类型。
                Object[] obj4 = a3; 
                Object[] obj5 = a4;
                System.out.println(a1);
                System.out.println(a4);
                 //Arrays.asList()方法处理int[]和String[]时的差异。int[]本身就是一个对象,把它看为一个整体。
                System.out.println(Arrays.asList(a1));     //[[I@efb549]
                System.out.println(Arrays.asList(a4));    //[a,b,c]
                 //Array工具类,用于完成对数组的反射操作。
                printObject(a1);
                printObject("xyz");
        }
        //自定义方法数组反射。 
        private static void printObject(Object obj) {
                Class clazz = obj.getClass();
                if(clazz.isArray()){
                        int len = Array.getLength(obj);
                        for(int i=0; i<len; i++){
                                System.out.println(Array.get(obj, i));
                        }
                }else{
                        System.out.println(obj);
                }
        }
         //自定义一个改变反射点对象的String变量值的方法。
        private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
                Field[] fields=obj.getClass().getFields();    //得到所有的成员变量
                for (Field field : fields) {    //遍历成员变量数组
                        //if(field.getType().equals(String.class)){
                        //字节码只有一份,用==比,语义更明确。
                        if(field.getType() == String.class) {    //如果成员变量的类型是String,则进行以下操作。
                                String oldValue = (String)field.get(obj);    //得到某一对象的成员变量
                                String newValue = oldValue.replace('b', 'a');    //把该变量的b字符换成a字符。
                                field.set(obj, newValue);    //把新的字符串赋给该对象的String变量。
                        }
                }
        }
}
//用发射来执行这个类
class TestArguments {
        public static void main(String[] args){
                for (String arg : args) {
                        System.out.println(arg);
                }
        }
}  
//定义一个反射点,专门用来做反射用。
import java.util.Date;
public class ReflectPoint {
        private Date birthday = new Date();
        private int x;
        public int y;
        public String str1="ball";
        public String str2="basketball";
        public String str3="itheima";
        public ReflectPoint(int x, int y) {
                super();
                this.x = x;
                this.y = y;
        }
        @Override
        //hashCode(),应用在底层必须是hash表的数据结构,先算出一个区域。 
        public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + x;
                result = prime * result + y;
                return result;
        }
        @Override
        //参数写成ReflectPoint pt,equals()为重载,不是覆盖。
        public boolean equals(Object obj) {
                if (this == obj)
                        return true;
                if (obj == null)
                        return false;
                if (getClass() != obj.getClass())
                        return false;
                ReflectPoint other = (ReflectPoint) obj;
                if (x != other.x)
                        return false;
                if (y != other.y)
                        return false;
                return true;
        }
        public int getX() {
                return x;
        }
        public void setX(int x) {
                this.x = x;
        }
        public int getY() {
                return y;
        }
        public void setY(int y) {
                this.y = y;
        }
        @Override
        public String toString() {
                return str1 + ":" + str2 + ":" + str3;
        }
        public Date getBirthday() {
                return birthday;
        }
        public void setBirthday(Date birthday) {
                this.birthday = birthday;
        }
}

8,hashCode()本质和内存泄露,面试重点。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
import java.util.TreeSet;

public class ReflectTest2 {
    public static void main(String[] args) throws Exception {
         //模拟一个框架,用反射来获取集合。                 
        InputStream ips = new FileInputStream("config.properties");    //  尽量面向父类或接口编程。 
        //实际开发中,没人用这种相对路径。 
        //解决方法1(最常用的):使用绝对路径,但不是硬编码,而是运算得出来的。javaWeb中getRealPath()(得到某个工程所在的实际磁盘位置)+内部路径(相对于这个工程的路径),这两个拼起来就得到配置文件的绝对路径。  
        //解决方法2:利用类加载器,装载classPath文件夹下的配置文件。 缺点:只能读出,不能写入。
            方案2的第一种方式: 
        //InputStream ips =
                    ReflectTest2.class.getClassLoader().getResourceAsStream( "com/itheima/day1/config.properties");
             这句不能以“/”打头。证明是一个相对路径,相对于classPath指定目录下。
        SSH三大框架内部用的就是类加载器加载的原理,所以他的配置文件放在classPath指定的路径下。
            
方案2的第二种方式:  
        //利用CLass提供的方法直接获取配置文件,书写更简便。
        //InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
        直接用类提供的方法更聪明,它相对与所在的包下面。 
        当然用类提供的方法也可以使用绝对 路径,以“/"打头,表示相对于classpath的根目录,与类加载器道理一样了。
InputStream ips = ReflectTest2.class.getResourceAsStream("/com/itheima/day1/resources/config.properties");
 

        Properties props = new Properties();
        //Properties是一个增强的Map集合,可以直接从硬盘上获取key,value值到内存。
        props.load(ips);
        ips.close();    //用完马上关闭,否则会有内存泄露,不是对象不被释放而是对象关联的系统资源不被释放。对象ips的释放由java的垃圾回收器释放。
        String className = props.getProperty("className");
        Collection collections = (Collection)Class.forName(className).newInstance();
 
        Collection collections = new HashSet();     //这个集合来保证元素唯一,复写hashCode()和equals()方法。
        ReflectPoint pt1 = new ReflectPoint(3, 3);
        ReflectPoint pt2 = new ReflectPoint(5, 5);
        ReflectPoint pt3 = new ReflectPoint(3, 3);
        collections.add(pt1);
        collections.add(pt2);
        collections.add(pt3);
        collections.add(pt1);
        //更改变量y的值,利用hashCode()找不到pt1对象,pt1无法删除,造成内存泄露。 内存泄露,即某一对象不再用,它一直占用内存空间,而不被释放掉。
        pt1.y = 7;
        System.out.println(collections.remove(pt1));
        System.out.println(collections.size());
    }
}

9
,反射的主要应用:实现框架功能。例如  struts,spring,hibernate  。
 
例如:1) 在我们还没有写程序时,框架就已经写好了。
            2)
还有就是上述7中利用 反射Method方法调用别人类的main方法,当别人的类还没有定义出来时,我们的类就可以编译了。
 
框架和工具类的区别,工具类是被调用,框架是调用别人。
 
模拟一个框架。
    1)定义一个配置文件config.properties。 className=java.util.ArrayList。运行时用户只用改一下配置文件就Ola。
    2) 查看上述8的程序,用反射来模拟一个框架,实现集合创建。

10,反射的第二种应用:内省IntroSpector。用来对JavaBean操作。
        JavaBean是一个特殊的java类,这种java类内部的方法名称符合某种约定的规则。例如setAge(),getAge()。
         
一个符合JavaBean特点的类可以当普通类来用,但普通Java类不一定能当作JavaBean来处理。  
        
JavaBean主要用来传递数据信息,所以如果两个模块之间传递多个信息,可以将这些信息封装在JavaBean中。这种Java类的方法主要用于访问私有的字段。  
        JavaBean的特点:
        1)JavaBean必须是个公开的类,即它的访问权限必须是public的。 javaBean是为了给其他类来用,所以其方法一般都是Public类型的。 
        2)JavaBean必须具有一个无参数的构造方法。如果在JavaBean中定义了自定义的有参构造方法,就必须添加一个无参数的构造方法,否则将无法设置属性;如果没有定义自定义的有参构造方法,则可以利用编译器自动添加的无参构造方法。
        3)JavaBean一般将属性设置成私有的,通过使用getXXX()和setXXX()方法来进行属性的取得和设置。
        javaBean的属性是根据set,get方法得到的:去掉get和set后就是JavaBean类的属性,属性命名规则,如果第二个字母是小的,则把第一个字母变成小的Age-->age。如果第二个字母是大的,则第一个字母保持不变CPU-->CPU。
        接下来用内省的方式来完成对javaBean的操作。查阅下篇日记高新技术2。 
 

 
11,常用英语:
 
         java ee—— Java Platform Enterprise Edition
 
        IDE ——IntegratedDevelopment Environment, 集成开发环境
 
         jms —— Java 消息服务( JavaMessageService
 
         JMX —— JavaManagementExtensions ,即 Java 管理扩展
 
         JNDI—— JavaNamingandDirectoryInterface Java 命名和目录接口
 
 
------------ android培训 java培训 、期待与您交流!------------

详情请查看: http://edu.csdn.net/heima  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值