黑马程序员-Java高新技术

——-android培训java培训期待与您交流!———-

静态导入

  • import static:导入一个类中的某个静态方法或所有静态方法。如:import static java.lang.Math.max;,导入的是Math下的max方法。
package com.sergio.NewTecl;
//静态导入包中的所有静态方法
import static java.lang.Math.*;
//静态导入包中某个静态方法
//import static java.lang.Math.max;
/**
 * 静态导入例子
 * Created by Sergio on 2015-06-03.
 */
public class ImportStatic {
    public static void main(String[] args) {
        System.out.println(max(3, 7));//求租嗲之
        System.out.println(abs(4 - 3));//求绝对值
    }
}

可变参数

  • 只能出现在参数列表的最后;
  • ...位于变量类型和变量名之间,前后有无空格都可以;
  • 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
package com.sergio.NewTecl;

/**
 * 可变参数
 * Created by Sergio on 2015-06-03.
 */
public class VariableParam {
    public static void main(String[] args) {
        System.out.println(add(3, 6));
        System.out.println(add(3, 1, 93, 23));
    }

    public static int add(int x, int... args) {
        int sum = 0;
        for (int i = 0; i < args.length; i++) {
            sum += args[i];
        }
        return sum;
    }
}

foreach

  • 语法:for(type 变量名:集合变量名){...}
  • 注意事项:迭代变量必须在()中定义;集合变量可以是数组或实现了Iterable接口的集合类。
package com.sergio.NewTecl;

/**
 * foreach
 * Created by Sergio on 2015-06-03.
 */
public class ForEach {
    public static void main(String[] args) {
        int[] buf = new int[] {3, 5, 6, 4, 2, 8};
        int sums = 0;
        for (int sum : buf) {
            sums += sum;
        }
        System.out.println(sums);
    }
}

自动装箱拆箱

  • 基本数据类型封装成引用数据类型。
  • 引用数据类型拆箱成基本数据类型。
基本数据类型引用数据类型
byteByte
shortShort
intInteger
longLong
booleanBoolean
floatFloat
doubleDouble
charCharacter
  • 注意:在基本数据类型的范围类,装箱成引用数据类型的两个对象引用相同值,他们两个对象的值是相等的。
  • 共享设计模式:避免大量拥有相同内容的小类的开销,使大家共享一个类(元类)。
package com.sergio.NewTecl;

/**
 * 装箱与拆箱
 * Created by Sergio on 2015-06-03.
 */
public class AutoBox {
    public static void main(String[] args) {
        Integer i = 2;//装箱
        Integer i2 = 4;
        System.out.println(i + i2);//拆箱

        Integer i3 = 12;
        Integer i4 = 12;
        //在int范围内,i3和i4对象引用的值相等
        System.out.println(i3 == i4);
        Integer i5 = 138;
        Integer i6 = 138;
        //超出了int范围,i5和i6的引用值不相等。
        System.out.println(i5 == i6);
    }
}

枚举

  • 让某个类型的变量的取值只能为若干个固定值中的一个。
package com.sergio.NewTecl;

/**
 * 枚举应用示例
 * Created by Sergio on 2015-06-04.
 */
public class EnumTest1 {
    public static void main(String[] args) {
        WeekDay weekDay = WeekDay.FRI;
        System.out.println(weekDay.name());//枚举对象的名字
        System.out.println(weekDay.ordinal());//排列位置,从0开始
        System.out.println(WeekDay.valueOf("SUN"));//将字符串转成枚举对象
        System.out.println(WeekDay.values());//获得枚举元素的转化成数组
    }

    public enum WeekDay {
        SUN, MON, TUE, WED, THI, FRI, SAT
    }
}
  • 构造方法枚举
    public enum WeekDay {
        SUN(2), MON(), TUE, WED, THI, FRI, SAT;//枚举的元素相当于枚举类型的对象,
                                               // 初始化时可以按照参数构造方法带入
        //空构造方法
        private WeekDay() {
            System.out.println("first");
        }

        //带参数构造方法
        private WeekDay(int day) {
            System.out.println("second");
        }
    }
  • 抽象方法枚举
    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 long time;
        //枚举元素子类对象的构造方法
        private TrafficLamp(long time){
            this.time = time;
        }
    }

内省与JavaBean

  • 内省:IntroSpector。主要用于操作JavaBean。
  • JavaBean:特殊的Java类,类中的方法名称符合某种约定的规则。如:getAge()setAge(int age)像这种方法名称前面是get和set打头的规则的类这种方式叫做JavaBean,主要用于访问Java类中的私有字段。JavaBean的属性根据set和get方法名称来获知,如setAge,属性就为age,而并不是跟类的成员变量有关,看不到Java类的内部成员。
  • 两个模块间传递多个信息就是用JavaBean的方式,将这些信息封装到一个JavaBean中,这种JavaBean的实例对象称之为值对象(Value Object)。这些类中用私有字段存储,可以用setget的方法来获取或者设置这些值。
package com.sergio.NewTecl;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 内省的操作
 * Created by Sergio on 2015-06-08.
 */
public class JavaBeanDemo1 {
    public static void main(String[] args) throws Exception {
        JavaBeanTest jbt = new JavaBeanTest(3, 5);
        //要获取的JavaBean属性X
        String propertyName = "x";
        //获取JavaBean信息,get
        PropertyDescriptor pd = new PropertyDescriptor(propertyName, jbt.getClass());
        Method methodGetX = pd.getReadMethod();
        Object objValue = methodGetX.invoke(jbt);
        System.out.println(objValue);
        //set
        Object value = 4;
        Method methodSetX = pd.getWriteMethod();
        methodGetX.invoke(jbt, value);

        System.out.println(jbt.getX());
    }
}


class JavaBeanTest {
    private int x;
    public int y;

    JavaBeanTest(int x, int y) {
        this.x = x;
        this.y = y;
    }

    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;
    }
}

BeanUtils

  • 对JavaBean操作的封装工具类。
        //BeanUtils主要操作的值为字符串
        BeanUtils.getProperty(jbt, "x");
        BeanUtils.setProperty(jbt, "x", "9");
        //Map与BeanUtils的互操作。BeanUtils为值对象,而Map为键值对
        Map<String, Integer> map = new HashMap<String, Integer>();

        BeanUtils.setProperty(map, "name", "lisi");
        //PropertyUtils操作的本身的数据类型
        PropertyUtils.setProperty(jbt, "x", 9);

注解

  • 注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,javac编译器,开发工具和其他程序可以用反射来获取你写的类及各种元素上有无标记,根据获取到的标记去做相应的工作。
  • 标记可以加在包、类、字段、方法,方法的参数以及局部变量上。
  • @SuppressWarnings:阻止编译器的警告。@Deprecated:标记某个过时的类或方法。@Override:重载。
  • 注解相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先定义这个注解类。就像调用某个类类似,你的先开发好这个类。
    Unnamed QQ Screenshot20150609185131.png
  • @Retention元注解:类的保留生命周期阶段。取值为:RetentionPolicy.SOURCE、RetentionPolicy.Class(默认值)、RetentionPolicy.RUNTIME代表调用的生命周期。分别对应注解三个周期:java源文件->class文件->内存中的字节码
  • @Target元注解:注解的类可以作用在那个成分上(类、方法、接口等)。
  • 注解属性:注解相当于独特的类,而属性相当于这个类中的方法。定义方式:在注解中增加String color();@MyAnnotation(color="blue")
  • 数组类型的属性:int arrayAttr default {2,4};\@MyAnnotation(arrayAttr={2,3,4})\如果数组属性只有一个元素,这时候属性值的部分可以省略大括号。
  • 枚举的属性:EnumTest1.TrafficLamp lamp();\@MyAnnotation(lamp=EnumTest1.TrafficLamp.GREEN)。
  • 注解属性:MetaAnnotation annotationAttr() default 。@MetaAnnotation(“2”);\@AnnotationDemo(annotationAttr = @MetaAnnotation(“hz”), color = “red”, value = “12”, arrayAttr = {2, 3, 4})。
package com.sergio.NewTecl;

/**
 * 注解定义
 * Created by Sergio on 2015-06-09.
 */
public @interface MetaAnnotation {
    String value();
}


============================
package com.sergio.NewTecl;

/**
 * 注解定义
 * Created by Sergio on 2015-06-09.
 */
public @interface MetaAnnotation {
    String value();
}


=====================
package com.sergio.NewTecl;

/**
 * 注解与反射
 * Created by Sergio on 2015-06-09.
 */

@AnnotationDemo(annotationAttr = @MetaAnnotation("hz"), color = "red", value = "12", arrayAttr = {2, 3, 4})
public class AnnotationTest {
    //阻止编译器过时API警告
    @SuppressWarnings("deprecation")
    @AnnotationDemo(value = "23")//此注解color已经有了默认值,只需设置value即可
    public static void main(String[] args) {
        System.runFinalizersOnExit(true);//过期API

        if (AnnotationTest.class.isAnnotationPresent(AnnotationDemo.class)) {
            AnnotationDemo annotation =
                (AnnotationDemo) AnnotationTest.class.getAnnotation(AnnotationDemo.class);
            System.out.println(annotation.color());
            System.out.println(annotation.value());
            System.out.println(annotation.arrayAttr().length);
            System.out.println(annotation.lamp().nextLamp().name());
            System.out.println(annotation.annotationAttr().value());
        }
    }
}

泛型

  • JDK1.5出现的新特性,解决了安全问题,是一个类型安全机制。使用泛型集合,可以将一个集合的元素作为特定的类型,集合中只能存储同一个类型的对象,这样更安全;获取对象时,不需要做强制类型转换方便。
  • 定义格式:ArrayList<String> collection = new ArrayList<String>();<>此符号主要用来定义要确认的类型。
  • 去类型化:编译器生成的集合字节码会去掉泛型类型信息。
  • 术语:ArrayList泛型类型、ArrayList中的E称为类型变量或类型参数。
  • 泛型兼容性:Collection<String> c = new Vector();可以兼容;Collection c = new Vector<String>();可以兼容。
  • 泛型的参数化类型没有继承关系:Vector<String> v = new Vector<Object>();错误。
  • Collection<?> collection:此处的?是通配符,表示任意类型。
  • 泛型通配符上限:Vector<? extends Number> x = new Vector<Integer>(),表示通配符的类型是Number或者Number的子类。
  • 泛型通配符下限:Vector<? super Integer> = new Vector<Number>(),表示通配符类型是Integer或Integer的父类。
package com.sergio.NewTecl;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 泛型基础信息介绍
 * Created by Sergio on 2015-06-11.
 */
public class GenericDemo {
    public static void main(String[] args) throws Exception {
        //定义String类型的集合
        ArrayList<String> collection1 = new ArrayList<String>();
        collection1.add("abc");
        System.out.println(collection1.get(0));

        ArrayList<Integer> collection2 = new ArrayList<Integer>();
        //判断这两个对象的的字节码是否一样。结果是true,说明字节码一样,编译器生成的字节码会去掉类型信息
        System.out.println(collection1.getClass() == collection2.getClass());
        //使用反射往集合中添加String字符串内容
        collection2.getClass().getMethod("add", Object.class).invoke(collection2, "abc");
        System.out.println(collection2.get(0));

        printCollection(collection2);
    }

    //打印集合元素。此处的?是通配符,表示任意类型
    public static void printCollection(Collection<?> collection) {
        for (Object obj : collection) {
            System.out.println(obj);
        }
    }
}
package com.sergio.NewTecl;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 对集合进行迭代
 * Created by Sergio on 2015-06-11.
 */
public class GenericDemo1 {
    public static void main(String[] args) {
        HashMap<String, Integer> aMaps = new HashMap<String, Integer>();
        aMaps.put("zhansan", 23);
        aMaps.put("lisi", 43);

        Set<Map.Entry<String, Integer>> entrySet = aMaps.entrySet();
        for (Map.Entry<String, Integer> entry : entrySet) {
            System.out.println(entry.getKey() + ":::" + entry.getValue());
        }
    }
}
  • 异常中使用泛型:
    public <T extends Exception> sayException() throws T {
        try {

        } catch (Exception e) {
            throw (T) e;
        }
        return;
    }

泛型类型推断:

根据调用泛型方法时实际传递的参数类型或返回值的类型来对端:
1. 当某个类型变量只在整个参数列表中的所有参数和返回值的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,及直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。如:swap(new String[3], 3,4) -> static <E> void swap(E[] a, int i, int i)
2. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用调用方法时这多处的实际应用类型都对应同一种类型来确定。如:add(3, 5) -> static <T> T add(T a, T b)
3. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候去多个参数中的最大交集类型,如下面这句实际对应类型是Number,编译没有问题,只是运行时出问题:
fill(new Integer[3], 3, 5) -> static <T> void fill(T[] a, T v)
4. 当某个性类变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同类型,并且使用返回值,这时候优先考虑返回值的类型,例如:这面这句实际对应的类型是Integer,编译报告错误,将变量x的类型改为Number,则没有了错误,int x -(3, 3.5f) -> static <T> T add(T a, T b)
5. 参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没问题,而第二种情况则根据参数化的Vector类实例类型变量直接确定为String类型,编译将出现问题:copy(new Integer[5], new String[5]) -> static <T> void copy(T[] a, T[] b)

泛型的类和方法定义

  • 泛型类何时定义:当类中操作的引用数据类型不确定的时候,可以用泛型来完成扩展。
  • 定义泛型类和方法:
package com.sergio.NewTecl;

/**
 * 泛型接口
 * Created by Sergio on 2015-06-12.
 */
interface Inter<T> {
    void show(T t);
}
//实现接口
class InterImpl<R> implements Inter<R> {
    public void show(R r) {
        System.out.println("show::" + r);
    }
}

类加载器


  • 加载类的工具。将.class加载进JVM中然后进行处理。
  • Java虚拟机有多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap、ExtClassLoader、AppClassLoader。
  • BootStrap:类加载器也是Java类,而必须有一个类加载器不是Java类,而这正是BootStrap,嵌入在JVM里。
  • ExtClassLoader:主要加载具有父子关系的树状组织的对象如继承关系的类,加载父级的对象。
  • AppClassLoader:系统Java类加载器。
    Paste_Image.png

类加载器的委托机制

  • 当Java虚拟机要加载一个类时,有那个类加载器加载的情况如下:首先当前线线程的类加载器去加载线程中的第一个类;如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B;还可直接调用ClassLoaderClass()方法来制定某个类加载器去加载某个类。
  • 每个类加载器加载类时,优先委托给上级类加载器(如上面提到的BootStrap->ExtClassLoader->AppClassLoader优先级从左到右降低)。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,就抱ClassNotFoundException异常。
  • 获取类加载器名字:被加载器类.class.getClassLoader().getClass().getName()
  • 自定义类加载器必须要继承ClassLoader,并且实现findClass(String name)方法,使用指定的二进制名称查找类。

代理类

  • 为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理、日志、计算方法的运行时间、事务处理等等,这些功能可以通过代理来解决。编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加载系统功能的代码。
目标类:doSomeThing(){
           业务功能代码
}

代理类:doSomeThing(){
           //前置系统功能代码
           目标对象.doSomeThing()
           //后置系统功能代码 
}

2015-06-14_111227.png

AOP:系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面,交叉业务的编程问题即为面向方面编程,而代理就是来处理此问题。
动态代理技术:要为系统中各种接口的类增加代理功能,需要太多的代理类,而这时候可以通过JVM可以在运行期动态生成出类的字节码,而这可以被用作代理类,即为动态代理类。如果要动态生成代理类,而目标类没有实现接口,可以通过CGLIB第三方类库来生成,

package com.sergio.NewTecl;

import javax.xml.bind.SchemaOutputResolver;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 创建动态类及查看其构造方法和成员方法列表信息
 * Created by Sergio on 2015-06-14.
 */
public class ProxyTest {
    public static void main(String[] args) throws Exception {
        //获取代理类的字节码
        Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
        System.out.println(clazzProxy.getName());
        //构造方法
        Constructor[] constructors = clazzProxy.getConstructors();
        for (Constructor constructor : constructors) {
            //获取构造方法名称
            String name = constructor.getName();
            StringBuilder stringBuilder = new StringBuilder(name);
            stringBuilder.append('(');
            Class[] clazzParams = constructor.getParameterTypes();
            for (Class clazzParam : clazzParams) {
                stringBuilder.append(clazzParam.getName()).append(',');
            }
            if (clazzParams != null && clazzParams.length == 0) {
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            }
            stringBuilder.append(')');
            System.out.println(stringBuilder.toString());
        }

        //方法
        Method[] methods = clazzProxy.getMethods();
        for (Method methodor : methods) {
            //获取构造方法名称
            String name = methodor.getName();
            StringBuilder stringBuilder = new StringBuilder(name);
            stringBuilder.append('(');
            Class[] clazzParams = methodor.getParameterTypes();
            for (Class clazzParam : clazzParams) {
                stringBuilder.append(clazzParam.getName()).append(',');
            }
            if (clazzParams != null && clazzParams.length == 0) {
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            }
            stringBuilder.append(')');
            System.out.println(stringBuilder.toString());
        }


        System.out.println("开始创建实例对象");
        //获得构造方法,主要是现实InvocationHandler是个接口,调用处理处理程序
        Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
        //需要实现invocationHandler的接口方法,invoke接受的三个参数为:代理对象,代理对象的那个方法,代理对象方法的参数
        class MyInvocationHander1 implements InvocationHandler {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        }
        //动态创建代理对象
        Collection proxy1 = (Collection) constructor.newInstance(new MyInvocationHander1());
        proxy1.clear();//调用collection中的clear方法
        proxy1.size();

        //创建实例的第二种写法
        Collection proxy2 = (Collection) constructor.newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });

        //动态创建实例对象第三种写法,
        Collection proxy3 =
            (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),
                new Class[] {Collection.class},
                new InvocationHandler() {
                    ArrayList target = new ArrayList<>();

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long beginTime = System.currentTimeMillis();
                        Object retVal = method.invoke(target, args);
                        long endTime = System.currentTimeMillis();
                        System.out.println(method.getName() + "所用时间" + (endTime - beginTime));
                        return retVal;
                    }
                });
        proxy3.add("xyz");
        proxy3.add("lhm");
        System.out.println(proxy3.size());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值