第04天 java基础加强

今日内容介绍

u Xml的综合案例

u 注解

u 类的加载

u 动态代理

第1章   注解

1.1  注解概述

l  什么是注解:Annotation注解,是一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次

n  对比注释:注释是给开发人员阅读的,注解是给计算机提供相应信息的。

l  注解的作用:

  1. 编译检查:通过代码里标识注解,让编译器能够实现基本的编译检查。例如:@Override
  2. 代码分析:通过代码里标识注解,对代码进行分析,从而达到取代xml目的。
  3. 编写文档:通过代码里标识注解,辅助生成帮助文档对应的内容
  4. @Deprecated 表示被修饰的方法已经过时。过时的方法不建议使用,但仍可以使用。

1.2  JDK常见注解

1.2.1 常见注解

n  一般被标记位过时的方法都存在不同的缺陷:1安全问题;2新的API取代

  1. @Override  JDK5.0表示复写父类的方法;jdk6.0 还可以表示实现接口的方法
  2. @SuppressWarnings 表示抑制警告,被修饰的类或方法如果存在编译警告,将被编译器忽略

deprecation ,或略过时

rawtypes ,忽略类型安全

unused , 忽略不使用

unchecked ,忽略安全检查

null,忽略空指针

all,忽略所有

1.2.2 案例代码一

AnnotationDemo_01

public class AnnotationDemo_01 {

@Deprecated

public void init(){

}

}

AnnotationDemo_02

public class AnnotationDemo_02 {

}

// 情况1: jdk1.5表示复写父类的方法

class Parent_2_1{

public void init(){

}

}

class Son_2_1 extends Parent_2_1{

@Override

public void init() {

}

}

// 情况2:jdk1.6 表示方法实现接口声明的方法

interface Parent_2_2{

public void init();

}

class Son_2_2 implements Parent_2_2 {

@Override

public void init() {

}

}

AnnotationDemo_03

@SuppressWarnings("serial")

public class AnnotationDemo_03 implements java.io.Serializable {

@SuppressWarnings({ "unused", "null", "deprecation", "rawtypes" })

public static void main(String[] args) {

List list = new ArrayList();

String str = null;

str.toString();

new Thread().stop();

}

}

1.3      自定义注解

1.3.1 自定义注解--定义与使用

l  定义注解使用关键字: @interface

  1. 定义类: class
  2. 定义接口:interface
  3. 定义枚举:enum

// #1 定义注解

@interface MyAnno1{

}

l  定义带有属性的注解

//#2 定义含有属性的注解

@interface MyAnno2{

public String username() default "jack";

}

l  属性格式:修饰符  返回值类型  属性名()  [default 默认值]

  1. 修饰符:默认值 public abstract ,且只能是public abstract。
  1. 返回值类型:基本类型、字符串String、Class、注解、枚举,以及以上类型的一维数组
  1. 属性名:自定义
  2. default 默认值:可以省略

l  注解使用的注意事项:

  1. 注解可以没有属性,如果有属性需要使用小括号括住。例如:@MyAnno1 或 @MyAnno1()
  2. 属性格式:属性名=属性值,多个属性使用逗号分隔。例如:@MyAnno2(username="rose")
  3. 如果属性名为value,且当前只有一个属性,value可以省略。
  4. 如果使用多个属性时,k的名称为value不能省略
  5. 如果属性类型为数组,设置内容格式为:{ 1,2,3 }。例如:arrs = {"itcast","itheima"}
  6. 如果属性类型为数组,值只有一个{} 可以省略的。例如:arrs = "itcast"
  7. 一个对象上,注解只能使用一次,不能重复使用。

1.3.2 代码案例二

Anno_01.java

public @interface Anno_01 {

}

Anno_02.java

public @interface Anno_02 {

/* 格式:修饰符  返回值类型  属性名() default 默认值

* * 修饰符:public abstract

* * 返回值类型:基本类型、String、Class、注解、枚举,以及以上类型的一位数组

*  * 属性名:自定义

*  * 默认值:可以省略

*/

public abstract String username() default "默认值";

public int age() ;

public Class clazz();

public Anno_01 anno();

public Color color();

}

//枚举:相当于多例。Color.RED

enum Color{

RED,BLUE;

}

//自定义多例

class Color2{

private Color2(){

}

public static final Color2 RED = new Color2();

public static final Color2 BLUE = new Color2();

}

Anno_03.java

public @interface Anno_03 {

public String[] hobbies();

}

Anno_04.java

public @interface Anno_04 {

public String[] value();

}

TestAnnotation.java

@Anno_01

@Anno_02(username="jack", age=18,clazz=Date.class , anno=@Anno_01 , color = Color.RED )

//@Anno_03(hobbies={"抽烟","喝酒","烫头"})        //数组表示使用{}括住

@Anno_03(hobbies="抽烟") //如果只有一个值,{}可以省略

//@Anno_04(value={"a","b"})

//@Anno_04(value="a")

@Anno_04("a")               //只有一对属性时,属性名为value,可以省略属性名

//同一个对象中,同一个注解只能使用一次。

public class TestAnnotation {

}

1.3.3 自定义注解--解析和元注解

1.3.3.1       解析

如果给类、方法等添加注解,如果需要获得注解上设置的数据,那么我们就必须对注解进行解析,JDK提供java.lang.reflect.AnnotatedElement接口允许在运行时通过反射获得注解。

常用方法:

boolean isAnnotationPresent(Class annotationClass) 当前对象是否有注解

T getAnnotation(Class<T> annotationClass) 获得当前对象上指定的注解

Annotation[] getAnnotations() 获得当前对象及其从父类上继承的,所有的注解

Annotation[] getDeclaredAnnotations() 获得当前对象上所有的注解

测试

public class MyAnnoTest_5 {

public static void main(String[] args) {

boolean b = MyAnnoTest_4.class.isAnnotationPresent(MyAnno_1.class);

System.out.println(b);    //false

}

}

当运行上面程序后,我们希望输出结果是true,但实际是false。TestAnno2类上有@MyAnno1注解,但运行后不能获得,因为每一个自定义注解,需要使用JDK提供的元注解进行修饰才可以真正的使用。

1.3.3.2       元注解

元注解:用于修饰注解的注解。(用于修饰自定义注解的JDK提供的注解)

JDK提供4种元注解:

@Retention 用于确定被修饰的自定义注解生命周期

RetentionPolicy.SOURCE 被修饰的注解只能存在源码中,字节码class没有。用途:提供给编译器使用。

RetentionPolicy.CLASS 被修饰的注解只能存在源码和字节码中,运行时内存中没有。用途:JVM java虚拟机使用

RetentionPolicy.RUNTIME 被修饰的注解存在源码、字节码、内存(运行时)。用途:取代xml配置

@Target 用于确定被修饰的自定义注解 使用位置

ElementType.TYPE 修饰 类、接口

ElementType.CONSTRUCTOR  修饰构造

ElementType.METHOD 修饰方法

ElementType.FIELD 修饰字段

@Documented 使用javaDoc生成 api文档时,是否包含此注解 (了解)

@Inherited 如果父类使用被修饰的注解,子类是否继承。(了解)

修改注解类,在运行测试实例,输出结果为:true。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnno1{

}

1.3.4 案例代码三

AnnoParse_01.java

@MyAnno("测试数据")

public class AnnoParse_01 {

public static void main(String[] args) {

//运行时,获得指定类上面的注解,从而获得对应数据

boolean b = AnnoParse_01.class.isAnnotationPresent(MyAnno.class);

if(b){

MyAnno myAnno = AnnoParse_01.class.getAnnotation(MyAnno.class);

String value = myAnno.value();

System.out.println(value);

} else {

System.out.println("没有注解");

}

}

@MyAnno

public AnnoParse_01(){

}

@MyAnno

public void init(){

}

}

MyAnno.java

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/* 元注解:jdk提供一套注解,元注解用于修饰自定义注解。

* 用于控制自定义注解 使用位置、生命周期等基本信息。

*

* @Target 用于限定自定义注解使用位置

*      @Target(ElementType.CONSTRUCTOR) 只能在构造方法使用

*      @Target(ElementType.METHOD) 只能在普通方法使用

*      @Target(ElementType.FIELD) 只能在字段使用

*      @Target(ElementType.TYPE) 只能在类、接口使用

* @Retention 用于确定自定义注解生命周期

*      @Retention(RetentionPolicy.SOURCE)  自定义注解只在源码有效,编译之后将删除(class文件没有)。提供编译器使用

*      @Retention(RetentionPolicy.CLASS)   自定义注解只在源码和字节码有效,编译之后有,运行时内存没有。提供JVM使用

*      @Retention(RetentionPolicy.RUNTIME) 自定义注解在源码、字节码和内存都有效。【】提供程序使用,用于取代xml配置文件

*

*/

@Target({ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnno {

public String value() default "默认值";

}

 

1.4      综合案例

1.4.1 案例分析

l  模拟Junit测试,首先需要编写自定义注解@MyTest,并添加元注解,保证自定义注解只能修改方法,且在运行时可以获得。

l  其次编写目标类(测试类),然后给目标方法(测试方法)使用@MyTest注解

l  最后编写测试类,使用main方法模拟Junit的右键运行。

1.4.2 案例代码四

MyTest.java

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface MyTest {

}

Demo.java

public class Demo {

@MyTest

public void demo01(){

System.out.println("demo01");

}

//@MyTest

public void demo02(){

System.out.println("demo02");

}

@MyTest

public void demo03(){

System.out.println("demo03");

}

}

TestApp.java

import java.lang.reflect.Method;

public class TestApp {

public static void main(String[] args) throws Exception{

//模拟 右键运行

// 当前指定类,所有的方法,是否有@MyTest注解,如果有将运行

//1 当前类

Class clazz = Demo.class;

// * new 实例

Object obj = clazz.newInstance();

//2 获得所有的方法

Method[] allMethod = clazz.getMethods();

for(Method method : allMethod){

//3 判断方法上是否有指定的注解

boolean b = method.isAnnotationPresent(MyTest.class);

if(b){

// 4 如果有,运行类

method.invoke(obj);

}

}

}

}

第2章   类的加载

2.1  类加载--理论

l  类加载器:类加载器是负责加载类的对象。将class文件(硬盘)加载到内存生成Class对象。

所有的类加载器 都是  java.lang.ClassLoader 的子类

l  使用类.class.getClassLoader()  获得加载自己的类加载器

l  类加载器加载机制:全盘负责委托机制

全盘负责:A类如果要使用B类(不存在),A类加载器C必须负责加载B类。

委托机制:A类加载器如果要加载资源B,必须询问父类加载是否加载。

如果加载,将直接使用。

如果没有机制,自己再加载。

l  采用 全盘负责委托机制 保证 一个class文件 只会被加载一次,形成一个Class对象。

l  注意:

如果一个class文件,被两个类加载器加载,将是两个对象。

提示 com.itheima.Hello  不能强制成 com.itheima.Hello

h.getClass() -->A                 h.getClass()  -->B

自定义类加载,可以将一个class文件加载多次。

2.2  类加载--演示

2.2.1 案例代码五

ClassLoaderDemo_01

import org.junit.Test;

public class ClassLoaderDemo_01 {

@Test

public void demo01(){

// 确定引导类加载器,加载内容:rt.jar  (Runtime )

// * JDK固定配置信息,sun.boot.class.path 用于表示 引导类加载器所加载的内容

String paths = System.getProperty("sun.boot.class.path");

String[] allPath = paths.split(";");

for(String p : allPath){

System.out.println(p);

}

}

@Test

public void demo02(){

// 确定引导类加载器,类型:null

ClassLoader cl = String.class.getClassLoader();

System.out.println(cl);

}

}

ClassLoaderDemo_02.java

import org.junit.Test;

import sun.net.spi.nameservice.dns.DNSNameService;

public class ClassLoaderDemo_02 {

@Test

public void demo01(){

// 确定扩展类加载器,加载内容: jre/lib/ext

// * JDK固定配置信息,java.ext.dirs 用于表示 扩展类加载器所加载的内容

String paths = System.getProperty("java.ext.dirs");

String[] allPath = paths.split(";");

for(String p : allPath){

System.out.println(p);

}

}

@Test

public void demo02(){

// 确定扩展类加载器,类型:Launcher$ExtClassLoader

ClassLoader cl = DNSNameService.class.getClassLoader();

System.out.println(cl);

}

}

ClassLoaderDemo_03.java

import org.junit.Test;

import sun.net.spi.nameservice.dns.DNSNameService;

public class ClassLoaderDemo_03 {

@Test

public void demo01(){

// 确定应用类加载器,加载内容: 项目/bin (编译后内容) ,自己编写类由应用类加载加载

// * JDK固定配置信息,java.class.path 用于表示应用类加载器所加载的内容

String paths = System.getProperty("java.class.path");

String[] allPath = paths.split(";");

for(String p : allPath){

System.out.println(p);

}

}

@Test

public void demo02(){

// 确定应用类加载器,类型:Launcher$AppClassLoader

ClassLoader cl = ClassLoaderDemo_03.class.getClassLoader();

System.out.println(cl);

}

}

ClassLoaderDemo_04.java

import org.junit.Test;

import sun.net.spi.nameservice.dns.DNSNameService;

public class ClassLoaderDemo_04 {

@Test

public void demo01(){

//3个类加载的关系

ClassLoader c1 = ClassLoaderDemo_04.class.getClassLoader();

System.out.println(c1); //应用 (AppClassLoader)

ClassLoader c2 = c1.getParent();

System.out.println(c2); //扩展(ExtClassLoader)

ClassLoader c3 = c2.getParent();

System.out.println(c3); //引导(null)

}

}

第3章   动态代理

3.1  动态代理概述

java代理有jdk动态代理、cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包)

3.2      Proxy类

动态代理:程序运行时,使用JDK提供工具类(Proxy),动态创建一个类,此类一般用于代理。

代理:你 -- 代理(增强) -- 厂商

代理类: 目标类:被代理的

动态代理使用前提:必须有接口

Object proxyObj = Proxy.newProxyInstance(参数1,参数2,参数3);

参数1:ClassLoader,负责将动态创建类,加载到内存。 当前类.class.getClassLoader();

参数2:Class[] interfaces ,代理类需要实现的所有接口(确定方法),被代理类实例.getClass().getInterfaces();

参数3:InvocationHandler, 请求处理类,代理类不具有任何功能,代理类的每一个方法执行时,调用处理类invoke方法。

invoke(Object proxy ,Method ,Object[] args)

参数1:代理实例

参数2:当前执行的方法

参数3:方法实际参数。

3.3 
动态代理原理

3.4  动态代理案例

3.4.1 需求分析

自定一个MyCollections,在该类中定义一个unmodifiableList方法实现,使用动态代理对该方法增强,使list对象不能再加入元素。

3.4.2 案例代码六

MyCollections.java

public class MyCollections {

@SuppressWarnings({ "unchecked",
"rawtypes" })

public static
List<String> unmodifiableList(final
List<String> list) {

//list 所有功能都有 (目标类)

//proxyList 希望不能进行增删改,只能查询  (代理类)

// 参数1:ClassLoader ,动态代理需要一个类加载器

ClassLoader
loader = MyCollections.class.getClassLoader();

// 参数2:Class[]
interfaces 需要与目标类接口保持一致

Class[]
interfaces = list.getClass().getInterfaces();

List<String>
proxyList = (List<String>)Proxy.newProxyInstance(loader, interfaces,
new InvocationHandler(){

//代理类的每一个方法调用一次,处理类invoke方法都执行一次

@Override

public Object invoke(Object proxy, Method method,
Object[] args) throws
Throwable {

//处理(增强)--不允许添加

//1 获得方法名

String
methodName = method.getName();

//2 eq 不同方法的处理

if("add".equals(methodName)){

throw new
UnsupportedOperationException("操作不允许");

}

//处理类中直接执行目标类对应的方法

return method.invoke(list, args);

}

});

return proxyList;

}

}

ProxyDemo_01.java

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import org.junit.Test;

public class ProxyDemo_01 {

@Test

public void
demo01(){

List<String>
list = new
ArrayList<>();

list.add("abc");

String
s = list.get(0);

System.out.println(s);

List<String>
list2 = Collections.unmodifiableList(list);

String
s2 = list2.get(0);

System.out.println(s2);

list2.add("123");

//不支持操作异常,当前list2不允许修改。

//java.lang.UnsupportedOperationException

}

@Test

public void
demo02(){

List<String>
list = new
ArrayList<>();

list.add("abc");

String
s = list.get(0);

System.out.println(s);

List<String>
list2 = MyCollections.unmodifiableList(list);

String
s2 = list2.get(0);

System.out.println(s2);

list2.add("123");   //不允许

System.out.println(list2.size());

//不支持操作异常,当前list2不允许修改。

//java.lang.UnsupportedOperationException

}

}

java基础-day27的更多相关文章

  1. Java基础知识(壹)

    写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...

  2. [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)

    如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html   谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...

  3. 【JAVA面试题系列一】面试题总汇--JAVA基础部分

    JAVA基础 基础部分的顺序: 基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法 线程的语法,集合的语法,io 的语法,虚拟机方面的语法 每天几道,持续更新!! 1.一个". ...

  4. 最适合作为Java基础面试题之Singleton模式

    看似只是最简单的一种设计模式,可细细挖掘,static.synchronized.volatile关键字.内部类.对象克隆.序列化.枚举类型.反射和类加载机制等基础却又不易理解透彻的Java知识纷纷呼 ...

  5. java基础练习 字符串,控制流,日历,日期等

    1,对基本控制流程的一些练习 package org.base.practice3; import org.junit.Test; /** * Created with IntelliJ IDEA. ...

  6. Java基础知识【下】( 转载)

    http://blog.csdn.net/silentbalanceyh/article/details/4608360 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...

  7. Java基础知识【上】(转载)

    http://blog.csdn.net/silentbalanceyh/article/details/4608272 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...

  8. java基础学习03(java基础程序设计)

    java基础程序设计 一.完成的目标 1. 掌握java中的数据类型划分 2. 8种基本数据类型的使用及数据类型转换 3. 位运算.运算符.表达式 4. 判断.循环语句的使用 5. break和con ...

  9. Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)

    线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...

随机推荐

  1. Java并发-多线程面试(全面)

    1. 什么是线程?2. 什么是线程安全和线程不安全?3. 什么是自旋锁?4. 什么是Java内存模型?5. 什么是CAS?6. 什么是乐观锁和悲观锁?7. 什么是AQS?8. 什么是原子操作?在Jav ...

  2. iis日志分析软件及大文本切割软件下载

    在网上找了好几个日志分析软件,觉得这个是最简单.实用的,至少对我来说. 但这个软件有个缺点,就是日志比较大时,分析详细的会溢出,需要用到文本切割工具. 软件下载: iis日志分析软件 大文本切割软件 ...

  3. hdu 5491(2015合肥网赛)The Next

    题目;http://acm.hdu.edu.cn/showproblem.php?pid=5491 题意就是,T组测试数据.然后L,S1,S2.L的二进制中有x个1,x满足  S1<=x< ...

  4. JTable 查询

    public JTable query(String table) throws SQLException { DefaultTableModel tablemodel = new DefaultTa ...

  5. Android.Tools.Eclipse hangs at the Android SDK Content Loader

    Eclipse hangs at the Android SDK Content Loader http://stackoverflow.com/questions/13489141/eclipse- ...

  6. fedora 使用

    我们在这篇指南中将介绍安装Fedora 23工作站版本后要完成的一些实用操作,以便用起来更爽. 1.更新Fedora 23程序包 哪怕你可能刚刚安装/升级了Fedora 23,仍很可能会有需要更新的程 ...

  7. Windows 下 Phpstrom 配置git使用

    首先先去下载 git 下载链接 https://git-scm.com/download/winphpstrom 配置git    链接  http://jingyan.baidu.com/artic ...

  8. zz Alex's BLOG 串口连接

    using System; using System.Collections.Generic;using System.ComponentModel;using System.Data;using S ...

  9. Python之路(第一篇):Python简介和基础

    一.开发简介 1.开发:      开发语言:               高级语言:python.JAVA.PHP.C#..ruby.Go-->字节码                低级语言: ...

  10. rapidjson 的封装学习

    #pragma once #include "Util.h" #include "rapidjson/writer.h" #include "rapi ...