第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. python 数据类型 之 tuple 元组

    python 3.6.5 元组的特性和定义 与列表类型 只不过 [  ] 改成了() 特性: 1.不可变(元组本身不可变,但是可以存可变类型的element){猜测因为可变element的地址不可变而 ...

  2. 金老师的经典著作《一个普通IT人的十年回顾》

    学习人生             -------一个普通IT人的十年回顾(上)序从1994到2003,不知不觉之间,我已在计算机技术的世界里沉浸了十年.有位哲人说过:如果一个人能用十年的时间专心致志地 ...

  3. 【Linux系列】Ubuntu ping通,xshell无法连接

    现象描述:Ubuntu能Ping通主机,主机也能ping通虚拟机.而且,虚拟机也能上网.只是xshell不能连接. 解决方案: 一:使用管理员身份 设置防火墙. 先查看一下防火墙状态 sudo ufw ...

  4. PAT 1066 图像过滤(15)(代码)

    1066 图像过滤(15 分) 图像过滤是把图像中不重要的像素都染成背景色,使得重要部分被凸显出来.现给定一幅黑白图像,要求你将灰度值位于某指定区间内的所有像素颜色都用一种指定的颜色替换. 输入格式: ...

  5. Java.WeakReference-SoftReference-PhantomReference

    Weak Reference, Soft Reference, Phantom Reference 1. Introduction "Weak reference objects, whic ...

  6. Docker 介绍和使用

    Docker 技术可以实现容器装载软件和依赖库,类似于封闭的Linux系统,默认相当于有root权限,可以快速移植和部署到其他机器上. Docker 容器技术可以理解为:仓库(储物间),镜像(类似于面 ...

  7. OneZero第三周第一次站立会议(2016.4.4)

    1. 时间: 13:30--13:45  共计15分钟. 2. 成员: X 夏一鸣 * 组长 (博客:http://www.cnblogs.com/xiaym896/), G 郭又铭 (博客:http ...

  8. PSP(3.30——4.5)以及周记录

    1.PSP 3.30 12:00 13:00 10 50 Account前端 A Y min 13:00 13:20 0 20 站立会议 A Y min 15:15 17:00 20 85 Accou ...

  9. 2018.11.01 洛谷P3953 逛公园(最短路+dp)

    传送门 设f[i][j]f[i][j]f[i][j]表示跟最短路差值为iii当前在点jjj的方案数. in[i][j]in[i][j]in[i][j]表示在被选择的集合当中. 大力记忆化搜索就行了. ...

  10. MES制造执行系统

    mes :  Manufacturing Execution System 制造执行系统 起因:ERP系统和底层设备之间出现了断层. 包括资源管理,生产调度,单元分配,生产跟踪,性能分析,文档管理,人 ...