java高级2

Junit
    * 进行单元测试,可以直接运行普通方法(不通过main方法)
    * 步骤:
        1. 创建一个类(类名不要是Test)
        2. 创建一个方法,要求:必须是 public;没有返回值void;非静态的;方法名称自定义,无参
        3. 在方法上方添加@Test注解
        4. 在@Test上按ctrl+1,选择Add Junit 4 library to the build path
        5. 选中方法名称,右键run as-->junit test
        也可以: 右键-->new-->Junit Test Case,然后根据提示操作
        注意:如果不选择方法名称,则所有方法全部运行
        示例:
            import org.junit.Test;
            public class Student {
                @Test
                public void aaa(){
                    System.out.println("aaa");
                }
            }
    * @Test 如果想单独运行某个方法,则必须加此注解,否则报initializationError错误(运行全部方法时会忽略此方法)
    * @Ignore 如果使用此注解进行标记,表示忽略当前方法运行(不管有没有@Test)
    * @Before 加此注解的方法会在每个方法运行前先运行一遍(不用加@Test)
    * @After 加此注解的方法会在每个方法运行后再运行一遍(不用加@Test)
    * Assert类 断言,通过程序进行数据的校验,不正确就报错.此类提供了一些静态方法进行数据的校验



JDK5特性
    * Static Import 静态导入
        * 在一个类中通过静态导入,可以直接使用另一个类的静态资源(静态字段、静态方法)
        * 格式:import static 包.类.字段|方法名称|*
            例:import static java.util.Collections.sort; 
            使用时可直接调用,就像本类的静态成员一样
    * Autoboxing/Unboxing 自动装箱与拆箱,基本类型与包装类型的转换 
    * Varargs 可变参数
        在定义方式时将参数声明成可变参数,在调用时实际参数的个数不确定。
        声明可变参数格式:类型 ... 变量名称
        可变参数实质上是数组
        如果方法有多个参数,则可变参数只能写在参数列表最后
        示例:
            声明时: 
                void sum(int... a){
                void sum(String s,int... a){
            调用时:
                //可以传任意多的int参数,或传入一个int数组,但是不能int[]和 其它 同时传
                sum(1,2,3);         //sum()也可以
                sum(new int[]{1,2,3})
        可变参数 和 数组 不能构成重载
        当传入的参数不是数组时,将参数装到一个新数组中传递给方法;当传入的参数是一个数组时,直接传递过去
        注意Object...
            同时传入Object和Object[],则可变参数的长度为2,虚拟机会将Object[]也认为是一个Object类型的,然后装到一个新数组的其中一个元素中
            如果传入Object[],但这个Object[]的引用类型为Object,则也会装到新数组的其中一个元素中.所以注意一定要先强转
    * Generics 泛型
    * Enhanced for Loop 增强for循环
        格式:
            for(数据类型  变量名:数组或者collection集合){
                执行语句;
            }
        增强for循环 可以遍历实现了Iterable接口的类
        通常增强for循环只用于遍历目标(修改不方便,增删不能做)
        在遍历过程中可以进行修改操作,不能进行增删操作(会抛异常)
    * Typesafe Enums ,枚举
        枚举的意思是一个一个举例
        枚举就是多例的简化写法(不让你创建对象,只能使用本来定义的多个对象)
        枚举也是类
        定义方式:
            public enum 枚举类名{
                变量名,变量名...;
            }
        枚举成员的修饰词默认为:public static final
        注意:
            成员变量必须放置在类开始。
            枚举的构造方法必须私有
        枚举API
            枚举有一些默认的方法,可以将 枚举和字符串或整形进行相互转换
            对象.name()             枚举-->字符串
            对象.ordinal()          枚举-->整形
            类名.valueOf(str)       字符串-->枚举
            类名.values()[index]    整形-->枚举  values可返回所有枚举的数组,通过索引可获得指定枚举对象
        带成员变量和方法的枚举(了解)
            public enum Gender {
                male("男"),female("女");
                
                private String name;
                private Gender(String name){
                    this.name = name;
                }
                public String getName(){
                    return this.name;
                }
            }
            调用:
                Gender m1 = Gender.male;
                Gender f1 = Gender.female;
                System.out.println("m1 enum --> " + m1.getName());
                System.out.println("f1 enum --> " + f1.getName());
    * Annotations 注解
        注解就是一个类。用于取代xml配置文件。随着项目越来越庞大,xml配置文件中将存在大量的配置信息,导致程序难以维护与扩展。配置信息仍然存在,将使用注解进行配置
        注解本身没有任何作用,相对于一个记号,可以传递值,解析时根据值进行相应的操作
        应用:
            2.1声明注解(定义)
            2.2使用注解
            2.3解析注解(获得使用时添加的配置信息)
        JDK提供三个基本注解
            @Override : JDK5.0 表示子类对父类方法的复写。 JDK6.0开始还表示方法是实现接口的方法
            @Deprecated : 表示被修饰的方法已经过时,不建议使用(但还可以使用)
            @SuppressWarnings : 表示被修饰的对象,所确定的内容进行抑制编译器警告
                rawtypes , 类型安全警告
                unused , 未使用警告
                null , 空指针警告
                deprecation,使用过期方法的警告
                serial,实现序列号接口implements java.io.Serializable,但没有提供序列号警告
                all,所有内容警告
                建议:需要将所有的警告尽量去解决
        声明注解
            格式:修饰词 @interface 注解名{内容} //修饰词只能为public 或 abstract,不写默认为public
            内容格式:修饰符 类型 名称() [default 默认值];
                例如:public String username(); 
                类型:String字符串 / Class类对象 / 其他注解 / enum枚举 / 基本类型 , 以及以上类型对应的一维数组
                名称
                    使用时,”名称“称为属性attribute名称。
                    解析时,”名称“称为方法名称
            元注解
                用于修饰注解(自定义)的注解(JDK提供)。
                @Retention,被修饰的注解,生命周期。
                    @Retention(RetentionPolicy.SOURCE) ,表示被修饰的注解只存在于源码中。提供给编译器使用
                    @Retention(RetentionPolicy.CLASS),表示被修饰的注解只存在于源码和字节码文件中。提供给JVM(java虚拟机)使用
                    @Retention(RetentionPolicy.RUNTIME),表示被修饰的注解存在于源码、字节码文件或内存中。提供程序获得内容,最常使用
                @Target,被修饰的注解,修饰的对象。
                    @Target(ElementType.TYPE)   ,被修饰的注解,只能使用在【类、接口】等对象上
                    @Target(ElementType.CONSTRUCTOR),被修饰的注解,只能使用在【构造方法】对象上
                    @Target(ElementType.METHOD),被修饰的注解,只能使用在【方法】对象上
                    @Target(ElementType.FIELD),被修饰的注解,只能使用在【字段】对象上
                    注意:可以同时赋多个值,放到数组中
                @Documented 被修饰的注解,将存在于生成的JavaDoc中(在方法详细信息中可以看到,注意:注解应该在文档注释下方)
        使用注解
            使用格式:在修饰对象上方添加 @注解类名称(属性名称=值,属性名称={值1,值2})
            注意:
                修饰对象参见上面的<声明注解>中的<元注解>中的<@Target>
                如果定义类型为数组,使用需要使用花括号 {},多个值使用逗号分割。如果只有一个值,可以不写花括号
                如果使用时,属性只有一个,且名称为value,则value=可以省略
        解析注解
            AnnotatedElement接口(java.lang.reflect)
                被修饰的注解必须实现的接口
                已知实现类:java.lang.Class / java.lang.reflect.Constructor / java.lang.reflect.Method/ java.lang.reflect.Field
                方法
                    boolean isAnnotationPresent(Class<? extends Annotation> annotationType) 
                        当前对象是否被指定的注解annotationClass修饰
                    <T extends Annotation> T getAnnotation(Class<T> annotationType) 
                        如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
                    Annotation[] getAnnotations() 
                        返回此元素上存在的所有注解。 
                    Annotation[] getDeclaredAnnotations() 
                        返回直接存在于此元素上的所有注解。
            获取注解的值
                obj.方法名称();
        案例:使用注解配置JDBC连接参数
            创建注解
                @Retention(RetentionPolicy.RUNTIME)
                @Target(ElementType.METHOD)
                public @interface JdbcInfo {
                    public String driver();
                    public String url();
                    public String user();
                    public String password();
                }
            使用和解析注解
                public class JdbcUtils {
                    @JdbcInfo(driver = "com.mysql.jdbc.Driver",url = "jdbc:mysql://localhost:3306/ebookstore",user = "root",password = "1234")
                    public static Connection getConnection() throws Exception{
                        /**解析注解 start*/
                        // 1 获得方法
                        Method method = JdbcUtils.class.getMethod("getConnection");
                        // 2 在当前方法上判断是否有指定的注解
                        if(! method.isAnnotationPresent(JdbcInfo.class)){
                            return null;    //没有返回null
                        }
                        // 3 获得注解对象
                        JdbcInfo jdbcInfo = method.getAnnotation(JdbcInfo.class);
                        // 4 取值
                        String driver = jdbcInfo.driver();
                        String url = jdbcInfo.url();
                        String user = jdbcInfo.user();
                        String password = jdbcInfo.password();
                        /**解析注解 end*/
                        //手动的获得连接
                        // * 注册驱动
                        Class.forName(driver);
                        // * 获得连接
                        Connection conn = DriverManager.getConnection(url, user, password);
                        return conn;
                    }
                }
            测试
                public class TestDao {
                    public static void main(String[] args) throws Exception {
                        Connection conn = JdbcUtils.getConnection();
                        System.out.println(conn);
                        conn.close();
                    }
                }
        servlet3.0提供注解用于servlet,过滤器,监听器的配置,还提供注解支持文件上传.参见《Servlet-JSP相关》的<servlet3.0>



问题示例及说明
    * 方法的重载问题(类型转换和自动装箱问题)
        public static void print(int i){        
            System.out.println("1 int ");
        }
        
        public static void print(double i){
            System.out.println("2 double ");
        }
        
        public static void print(Integer i){
            System.out.println("3 Integer ");
        }
        
        public static void print(Double i){ 
            System.out.println("4 Double ");
        }

        1. 调用print(100),结果是什么
        2. 注释掉第一个方法,调用print(100),结果是什么
        3. 注释掉前两个方法,调用print(100),结果是什么
        4. 注释掉前三个方法,调用print(100),结果是什么


        答案:
            1. 输出1 int,类型匹配
            2. 输出2 double,基本类型 自动 向上转型
            3. 输出3 Integer,装箱
            4. 报错,装箱 Integer 不能 转成 Double
    * 反射调用参数为数组的方法的问题(可变参数问题)
        如:反射调用main方法
            Method method = clazz.getMethod("main", String[].class);//clazz为某个类的字节码对象
            String[] arr = {"1"};
            method.invoke(null, arr);
        为什么报错?
            invoke第二个参数为可变参数形式,接收值为Object
            猜想:
                invoke在内部遍历可变数组,然后把其中的每个元素传递给方法的形参
                所以,要调用main方法则:
                传递给invoke的第二个参数必须是一个数组,而数组的第一个元素是一个String[]类型
                也可以先将String[]类型强转为Object类型,则可变参数自动将此String[]类型放置到一个新数组的第一个元素.
    * 关于this的问题
        public class parent{
            public void init(){
                System.out.println(1);
                this.demo();
            }
            public void demo(){
                System.out.println(2);
            }
        }
        public class Son extends Parent{
            public void init(){
                super.init();
                System.out.println(3);
                this.demo();
            }
            public void demo(){
                System.out.println(4);
            }
            public static void main(String[] args){
                Son son = new Son();
                son.init();
            }
        }
        输出结果:
            1 4 3 4
        就算是super调用了父类方法,但父类方法运行时的this仍是子类对象



类加载器 ClassLoader
    java.lang.ClassLoader 类加载器是负责加载类的对象。将class文件转换成Class对象
    类加载器获得方式:类.class.getClassLoader()
    加载器结构
        StrapClassLoader,引导类加载器
            加载内容:rt.jar    --> runtime运行时必须资源。(包含内容:java.lang | java.util | java.sql 等)
            对象:null          --> 不是类
        ExtClassLoader,扩展类加载器
            加载内容:jre\lib\ext 所有内容
            对象:sun.misc.Launcher$ExtClassLoader
        AppClassLoader ,应用类加载器
            加载内容:\WEB-INF\classes 所有内容(源码对应字节码) 、\WEB-INF\lib 使用第三方jar
            对象:sun.misc.Launcher$AppClassLoader
        可以通过System.getProperty()获得加载的内容,key分别为sun.boot.class.path, java.ext.dirs, java.class.path
        我们的程序由应用类加载器加载,应用类加载器由扩展类加载器加载,扩展类加载器由引导类加载器加载,引导类加载器不是类,是由c语言编写的
    classloader 加载类用的是全盘负责委托机制
        全盘负责:如果一个类A不在内存,当前类B如果要使用类A,必须使用当前类B的类加载器,去加载类A
        委托机制:一个类加载器如果要加载资源,必须先询问父加载器是否加载资源,如果已经加载则直接使用。否则在加载。
        将保证每一个类在内存中只会被加载一次。



动态代理 Proxy
    动态代理:在程序运行时,动态的创建一个代理类,对目标类进行代理,从而对目标方法进行增强。
    静态代理:编写方法(装饰者) -- 创建一个类
    JDK 提供java.lang.reflect.Proxy工具类,用于创建动态代理类,前提:必须有接口
        Object obj = Proxy.newProxyInstance(ClassLoader loader ,Class[] interfaces)
            返回值obj就是代理类对象,可以强转为接口类型,当做接口的实现类使用
            参数1:loader ,使用指定类加载器加载代理类对象. 通常为 当前类名.class.getClassLoader()
            参数2:interfaces , 要代理的接口,会根据接口创建一个空的代理类. 通常为 原接口实现类对象.getClass().getInterfaces()
            参数3:InvocationHandler ,InvocationHandler接口的实现类,要重写接口中的invoke方法,指定当使用代理类调用方法时的操作
                需要重写invoke方法
                Object invoke(Object proxy, Method method, Object[] args)
                    参数1 proxy : 代理对象
                    参数2 method :当前执行的方法
                    参数3 args : 当前执行方法实际参数。
                    返回值会作为调用接口方法的返回值
                    获得方法名称:method.getName()
                    执行目标类方法:method.invoke(目标类,args)
    示例
        接口
            interface IHello{
                public void sayHello();
                public void sayBye();
            }
        实现类
            class Hello implements IHello{
                public void sayHello() {
                    System.out.println("原始Hello方法");
                }
                public void sayBye() {
                    System.out.println("原始Bye方法");
                }
            }
        代理并测试
            public static void main(String[] args) {
                final IHello hello = new Hello();
                IHello myHello = (IHello)Proxy.newProxyInstance(
                        TestProxy.class.getClassLoader(), //使用指定类加载器加载代理类对象
                        hello.getClass().getInterfaces(), //要代理的接口
                        new InvocationHandler() {         //代理类对象方法被调用时,执行invoke方法
                            public Object invoke(Object proxy, Method method, Object[] args)
                                    throws Throwable {
                                //如果是sayHello方法,则执行自定义代码
                                if(method.getName().equals("sayHello")){
                                    System.out.println("增强Hello方法");
                                    return null;
                                }
                                //其它方法执行原实现类代码
                                method.invoke(hello, args);
                                return null;
                            }
                        });
                myHello.sayHello();
                myHello.sayBye();
            }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值