您的位置:首页 > 职场人生

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

2013-05-23 17:47 225 查看
------------android培训java培训、期待与您交流!------------ 
  

 1,JDK1.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)Class.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 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息