day_52 Java高级
一、XML
Xml格式的文件在接下来的框架学习尤为重要,比如在框架中的配置文件大多都是用的xml格式的文件来配置的,所以xml格式的文件创建与解析特别重要。
- XML概念
- XML(eXtensible Markup Language)是一种可扩展标识语言,是一种简单的数据存储语言,使用一系列简单的标记描述数据。目前推荐遵循的是W3C组织于2000年发布的XML1.0版本。
- XML语法规则
- 声明标签定在首行:<?xml version=“1.0” encoding=“utf-8|gb2312”?>
- 文档有且只有一个根元素
- 非空元素都必须有一对标签:起始/关闭标签
- 空元素的标签中同时表示起始和结束标签</>
- 大小写敏感
- 标签必须正确地嵌套
- 元素的属性必须有属性值且属性值必须加引号(单引或双引都可以)
- 在 XML 中,应使用实体引用来代替特殊字符
- 实体引用
- < 小于号< 【必须】
- > 大于号>
- & 和号& 【必须】
- ' 单引号‘
- " 双引号”
- 元素命名规则
- 名称可以含字母、数字以及其他的字符
- 名称不能以数字或者标点符号开始
- 名称不能以字符 “xml”(或者 XML、Xml)开始
- 名称不能包含空格
- 可使用任何名称,没有保留的字词
- XML的特点
- XML 仅仅是纯文本
- XML 的设计宗旨是传输数据,而非显示数据
- XML 是独立于软件和硬件的信息传输工具
- XML 标签没有被预定义,需要自行定义标签
- Dom4j概念
- dom4j是一个Java的XML API,是jdom的升级品,用来读写XML文件的。dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面还可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,所以可以知道dom4j无论在哪个方面都是非常出色的。如今可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这已经是必须使用的jar包, Hibernate也用它来读写配置文件。
- XML文档示例
<?xml version="1.0" encoding="UTF-8"?><books><!--This is a test for dom4j, holen, 2004.9.11--><book show="yes"><title>Dom4j Tutorials</title></book><book show="yes"><title>Lucene Studing</title></book><book show="no"><title>Lucene in Action</title></book><owner>O'Reilly</owner></books>
- 解析XML文档
- 解析/创建都是基于dom4j实现
public static void main(String[] args) throws DocumentException {File file = new File("hello.xml");SAXReader sax = new SAXReader();Document doc = sax.read(file);Element rootElement = doc.getRootElement();String name = rootElement.getName();System.out.println("根节点="+name);//判断是否是根节点System.out.println(rootElement.isRootElement());Iterator it = rootElement.elementIterator();while(it.hasNext()){Element ele = (Element)it.next();String eleName = ele.getName();if(eleName.equals("book")){Attribute attribute = ele.attribute(0);System.out.println(attribute.getName()+"="+attribute.getValue());Iterator it2 = ele.elementIterator();while(it2.hasNext()){Element ele2 = (Element)it2.next();System.out.println(ele2.getName()+"="+ele2.getText());}}else{System.out.println(ele.getText());}}}
- 解析/创建都是基于dom4j实现
- 创建XML文档
public static void main(String[] args) throws IOException, XMLStreamException {Document document = DocumentHelper.createDocument();Element booksElement = document.addElement("books");booksElement.addComment("This is a test for dom4j, holen, 2004.9.11");Element bookElement = booksElement.addElement("book");bookElement.addAttribute("show","yes");Element titleElement = bookElement.addElement("title");titleElement.setText("Dom4j Tutorials");/** 类似的完成后两个book */bookElement = booksElement.addElement("book");bookElement.addAttribute("show","yes");titleElement = bookElement.addElement("title");titleElement.setText("Lucene Studing");bookElement = booksElement.addElement("book");bookElement.addAttribute("show","no");titleElement = bookElement.addElement("title");titleElement.setText("Lucene in Action");/** 加入owner节点 */Element ownerElement = booksElement.addElement("owner");ownerElement.setText("O'Reilly");//用于格式化xml内容和设置头部标签OutputFormat format = OutputFormat.createPrettyPrint();//设置xml文档的编码为utf-8format.setEncoding("utf-8");Writer out = new FileWriter("hello2.xml");XMLWriter writer = new XMLWriter(out,format);writer.write(document);writer.close();}
二、反射
反射定义
反射即反向探知,有点像考古学家根据发掘的物品来探知以前的事情。
程序中的反射指程序运行状态中,
1、对于给定的一个类(Class)对象,可以获得这个类(Class)对象的所有属性和方法;
2、对于给定的一个对象(new XXXClassName<? extends Object>),都能够调用它的任意一个属性和方法。
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做Java反射机制
反射初识
public class User {public void eat(){System.out.println("---eat---");}}public class TestReflect{public static void main(String[] args) throws Exception {Class<User> clazz = User.class;//获取类对象对应的属性和方法System.out.println(clazz.getName());System.out.println(clazz.getPackage());System.out.println(clazz.getSuperclass());System.out.println(clazz.getClassLoader());//获取一个对象实例User user = clazz.newInstance();Method method = clazz.getDeclaredMethod("eat");method.invoke(user);}
为何用反射
直接new User()不就可以了,为什么要用这种反射写法?
实例化一个User()对象,不使用反射,如果想再实例化其他对象比如new Person(),那么
就需要修改源代码,并重新编译。使用反射后就不需要修改源代码只需要灵活改动类描述就
可以了,不需要重新再编译。 如下代码所示
//类描述,可根据需要实例化的描述而改动String className = "com.tledu.pojo.User";//使用反射中API创建对象Class.forName(className).newInstance();
反射的优缺点
优点:
增加程序的灵活性,避免固有逻辑写死到程序中
代码相对简洁,可以提高程序的复用性
缺点:
相比于直接调用反射有比较大的性能销毁
内部暴露和安全隐患
灵活性测试
public interface Ball {void playBall();}public class BasketBall implements Ball{@Overridepublic void playBall() {System.out.println("打篮球");}}public class FootBall implements Ball{@Overridepublic void playBall() {System.out.println("踢足球");}}//----------------------------public static void main(String[] args) {//System.out.println(getInstanceByKey("basket"));System.out.println(getInstanceReflectByKey("FootBall"));}public static Ball getInstanceByKey(String key) {if("foot".equals(key)){return new FootBall();}if("basket".equals(key)){return new BasketBall();}return null;}
如果我们想在添加一个乒乓球那么除了创建一个乒乓球类,还需要在方法中加入获取乒乓球对应的判断和乒乓球创建对象的返回,很显然不够灵活出现了写死代码的情况。
public static Ball getInstanceReflectByKey(String key) {String basePackage = "com.tledu.mjw";Ball ball = null;try {Class clazz = Class.forName(basePackage + "." + key);ball = (Ball)clazz.newInstance();} catch (Exception e) {e.printStackTrace();}return ball;}
使用反射的方式获取对象,可以看出代码灵活了很多而且不需要改动创建返回对象的源码。
性能测试
public static void main(String[] args) {//System.out.println(getInstanceByKey("basket"));//System.out.println(getInstanceReflectByKey("FootBall"));long start = System.currentTimeMillis();for (int i = 0; i < 1000000; i++){getInstanceByKey("basket");//getInstanceReflectByKey("FootBall");}long end = System.currentTimeMillis();System.out.println("耗时:" + (end - start));}
为什么这么慢呢?(分别查看forName()方法和newIntance()方法源码分析)
1、调用了native方法
2、每次调用newInstance()方法都会做安全检查,比较耗时
反射的操作
获取类对象的四种方式
//获取类对象的四种方式Class<User> clazz1 = User.class;Class<?> clazz2 = Class.forName("com.tledu.mjw.User");Class<? extends User> clazz3 = new User().getClass();Class<?> clazz4 = Demo3.class.getClassLoader().loadClass("com.tledu.mjw.User");
类中基本信息的获取
System.out.println(clazz1.getClassLoader());System.out.println(clazz1.getSuperclass());System.out.println(clazz1.getPackage());System.out.println(clazz1.getModifiers()); //获取类的修饰符System.out.println(clazz1.getName());System.out.println(clazz1.getSimpleName());System.out.println(clazz1.getInterfaces().length);//获取类实现的所有接口System.out.println(clazz1.getAnnotations().length);
类中字段的操作
创建User类继承Person类添加相应属性
public class Person {public String idCard;private String userName;}public class User extends Person{private String name;public String sex;public static String address;public void eat(){System.out.println("---eat---");}}
测试方法调用
public static void main(String[] args) throws Exception {Class<User> userClass = User.class;User user = userClass.newInstance();//getFields()获取的是本类及父类中的公共属性Field[] fields = userClass.getFields();for (Field field : fields) {System.out.println(field.getModifiers() + " " + field.getName());}System.out.println("---------------");//getDeclaredFields()获取本类中的所有属性Field[] fields2 = userClass.getDeclaredFields();for (Field field : fields2) {System.out.println(field.getModifiers() + " " + field.getName());}System.out.println("---------------");//获取name字段对应的fieldField nameField = userClass.getDeclaredField("name");//如果需要修改私有属性信息那么我们要放开权限nameField.setAccessible(true);nameField.set(user,"天亮教育");System.out.println(nameField.get(user));//System.out.println(user.getName());System.out.println("---------------");//如何对静态的属性赋值Field addressField = userClass.getDeclaredField("address");addressField.set(null,"Jack");System.out.println(addressField.get(null));//System.out.println(User.address);}
类中方法的操作
在User类中将eat方法改为私有的,并添加静态方法say
private void eat(){System.out.println("---eat---");}public static void say(String msg){System.out.println(msg);}
在Person类中添加共有的fn1()方法和私有的fn2()方法
public void fn1(){}private void fn2(){}
测试方法调用
public static void main(String[] args) throws Exception {Class<User> userClass = User.class;User user = userClass.newInstance();//获取本类及父类中的公共方法Method[] methods1 = userClass.getMethods();for (Method method : methods1) {System.out.println(method.getModifiers() + " " + method.getName());}System.out.println("--------------");//获取本类中所有的方法包括私有Method[] methods2 = userClass.getDeclaredMethods();for (Method method : methods2) {System.out.println(method.getModifiers() + " " + method.getName());}System.out.println("--------------");//调用方法执行Method eatMethod = userClass.getDeclaredMethod("eat");//调用私有方法时要先开放权限eatMethod.setAccessible(true);eatMethod.invoke(user);System.out.println("--------------");//调用静态的方法Method sayMethod = userClass.getDeclaredMethod("say",String.class);sayMethod.invoke(null,"你好");}
类中构造器的操作
在User中添加如下构造方法
public User() {}public User(String name) {this.name = name;}private User(String name,String sex) {this.name = name;this.sex = sex;}
通过反射操作User中的构造方法
public static void main(String[] args) throws Exception {Class<User> userClass = User.class;//获取公共的构造器Constructor<?>[] constructors = userClass.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor.getModifiers() + " " + constructor.getName());}System.out.println("------------------");//获取所有的构造器Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor.getModifiers() + " " + declaredConstructor.getName());}//1、直接通过newInstance创建对象User user = userClass.newInstance();//2、获取对应的Constructor对象获取实例Constructor<User> constructor = userClass.getDeclaredConstructor(String.class, String.class);//操作私有的构造器要先打开权限constructor.setAccessible(true);User user1 = constructor.newInstance("乔森", "男");}
- 反射破局单例
单例模式
public class PersonSingle {private static PersonSingle instance = null;private PersonSingle(){}public static PersonSingle getInstance(){if(instance == null){instance = new PersonSingle();}return instance;}}
测试单例、通过反射可以调用私有构造
public static void main(String[] args) throws Exception {PersonSingle instance1 = PersonSingle.getInstance();PersonSingle instance2 = PersonSingle.getInstance();PersonSingle instance3 = PersonSingle.getInstance();System.out.println(instance1);System.out.println(instance2);System.out.println(instance3);System.out.println("---------------------");Class<PersonSingle> personSingleClass = PersonSingle.class;Constructor<PersonSingle> declaredConstructor = personSingleClass.getDeclaredConstructor();declaredConstructor.setAccessible(true);System.out.println(declaredConstructor.newInstance());}
改进单例如下
private PersonSingle(){if(instance != null){throw new RuntimeException("实例已经存在不允许再创建")}}
- 反射使用场景
- jdbc封装
- SpringIOC
- JdbcTemplate
- Mybatis
三、注解
注解的概念
注释:用文字描述程序,给程序员看的
/** 多行注释*/// 单行注释
注解:说明程序的,给计算机看的
定义:
注释(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用:
- 编写文档:通过代码里标识的注释生成文档【生成doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
- 生成文档演示:
创建User类
/*** 注解JavaDoc描述* @author mark* @since jdk1.5* @version 1.0*/public class User {private Integer id;private String userName;@Overridepublic String toString() {return "User{" +"id=" + id +", userName='" + userName + '\'' +'}';}/*** 两数相加* @param a 第一个整数* @param b 第二个整数* @return 返回两数和*/public int add(int a,int b){return a+b;}}
执行命令生成说明文档:javadoc User.java
JDK预定义的注解
@Override:检查被该注解标注的方式是否是继承自父类【接口】
@Deprecated:该注解表示注释的内容过时
@SuppressWarnings:压制警告
代码演示:
import java.util.Date;@SuppressWarnings("all")public class AnnoDemo01 {@Overridepublic String toString() {return "AnnoDemo01{}";}@Deprecatedpublic void show1(){//发现过时了,功能跟不上需求了}//@SuppressWarnings("all")public void show2(){//功能更加强大的方法}public void demo(){show1(); //不推使用但可以使用//show2();Date date = new Date();date.getYear();}}
自定义注解
查看jdk预定义的注解源码发现格式如下
public @interface 注解名{ }
自定义注解 MyAnno
public @interface MyAnno{ }
执行javac MyAnno.java 生成MyAnno.class
执行javap MyAnno.java 将class文件反编译
Compiled from "MyAnno.java"public interface MyAnno extends java.lang.annotation.Annotation {}
注解的本质其实就是一个接口,继承Annotation父接口
属性:在接口中定义的抽象方法
public @interface MyAnno{String show1();Int show2();String[] show3();MyAnno2 show4();PsersonEnum show5(); }
返回结果必须是如下类型
- 基本数据类型
- String类型
- 枚举类型
- 注解
- 以上类型的数组
如何来用这些属性呢?
public @interface MyAnno{String name();int age(); //default 18; }
赋值给属性
@MyAnno(name="tom",age=18)public void demo(){ }
如果注解类中的属性是value且只有一个属性,那么可以再赋值的时候省去value
public @interface MyAnno{String value();//String name();//int age(); //default 18; }
给注解中只有一个value的属性赋值
//@MyAnno(value="tom")@MyAnno("tom")public void demo(){ }
在注解类中添加注解类型、枚举类型、数组类型的属性并赋值
public @interface MyAnno{String value();String[] show3();MyAnno2 show4();PsersonEnum show5(); }
给不同类型的属性赋值
//@MyAnno(value="tom")@MyAnno(value="tom",show3={“a”,”b”},show4=@MyAnno2,show5=PsersonEnum.name})public void demo(){ }
属性赋值注意点:
- 如果定义属性时,使用default关键字给属性默认初始值,可以在使用注解时不赋值
- 如果只有一个属性需要赋值,而且该属性的名称是value,那么赋值时value可以省略
- 数组赋值的时候,使用{}括起来,如果数组中只有一个值,那么{}可以省略
元注解
JDK中给我们提供的4个元注解
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface MyAnno2 {}
- @Target:描述当前注解能够作用的位置
ElementType.TYPE: 可以作用在类上
ElementType.METHOD:可以作用在方法上
ElementType.FIELD: 可以作用在成员变量上
- @Retention:描述注解被保留到的阶段
SOURCE<CLASS<RUNTIME
SOURCE:表示当前注解只在代码阶段有效
CLASS:表示该注解会被保留到字节码阶段
RUNTIME:表示该注解会被保留到运行阶段JVM
自定义的注解:RetentionPolicy.RUNTIME
@Documented:描述注解是否被抽取到JavaDoc api中
- @inherited:描述注解是否可以被子类继承
- @Target:描述当前注解能够作用的位置
- 自定义注解案例
创建InvokAnno注解
/*** 自定义注解* 该注解表示要执行哪个类中的哪个方法*/@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface InvokAnno {String className();String methodName();}
创建Student1类
public class Student1 {public void show(){System.out.println("show1方法");} }
创建MyMain测试类进行测试
@InvokAnno(className = "com.tledu.anno2.Student2",methodName = "show")public class MyMain {public static void main(String[] args) throws Exception {Class<MyMain> clazz = MyMain.class;InvokAnno anno = clazz.getAnnotation(InvokAnno.class);/*** 注解本质是接口 获取到的其实是接口实现* public class MyInvokAnno implements InvokAnno{* String className(){* return "com.tledu.anno2.Student1";* }* String methodName(){* return "show1";* }* }*/String className = anno.className();String methodName = anno.methodName();Class<?> aClass = Class.forName(className);Method method = aClass.getDeclaredMethod(methodName);Object o = aClass.newInstance();method.invoke(o);}}
day_52 Java高级相关推荐
- Java高级特性增强-多线程
请戳GitHub原文: https://github.com/wangzhiwub... 大数据成神之路系列: 请戳GitHub原文: https://github.com/wangzhiwub... ...
- java基础(十三)-----详解内部类——Java高级开发必须懂的
java基础(十三)-----详解内部类--Java高级开发必须懂的 目录 为什么要使用内部类 内部类基础 静态内部类 成员内部类 成员内部类的对象创建 继承成员内部类 局部内部类 推荐博客 匿名内部 ...
- Java高级特性:clone()方法
标签:ringbuf his 硬件 throws port protect 序列化 ext this 目录 源码 深拷贝和浅拷贝 对象串行化实现拷贝 常见面试题 源码 ...
- Java高级技术笔记
Java高级技术笔记 URL地址 HTTP协议 开发工具 Java开发工具包(JDK) JSP引擎 MyEclipse IDEA 工具集成 C/S架构是Client/Server的简写,也就是客户机/ ...
- Java高级程序员(5年左右)面试的题目集
Java高级程序员(5年左右)面试的题目集 https://blog.csdn.net/fangqun663775/article/details/73614850?utm_source=blogxg ...
- 为什么3年的Java高级程序员薪水仅仅8k-10k,而一个Linux底层C语言程序员两年经验就敢要1...
为什么80%的码农都做不了架构师?>>> 为什么3年的Java高级程序员薪水仅仅8k-10k,而一个Linux底层C语言程序员两年经验就敢要10k的薪水? 由于目前国内嵌入 ...
- 面试 Java 高级后端开发,要准备哪些知识点?
由于我做了比较长时间的技术面试官,根据我的面试体会,不少同学收到面试后,什么准备也不会做,到时候就来了. 这样做的后果是:不知彼,不知己,每战必殆.哪怕侥幸面试成,工资一定会被压得很低. 其实公司肯花 ...
- 如何才能成为java高级程序员?
身为程序员,一旦进入技术行列,就开启了持续学习的道路,更迭迅速的互联网时代,技术自然也是一代一代的更新,在技术进阶的道路上,要不断吸收新的想法和技术知识. 牛逼的人总是让人羡慕,但如何才能让自己成为牛 ...
- Java高级开发工程师面试笔记
最近在复习面试相关的知识点,然后做笔记,后期(大概在2018.02.01)会分享给大家,尽自己最大的努力做到最好,还希望到时候大家能给予建议和补充 ----------------2018.03.05 ...
最新文章
- java用1234组成,用javasecp代码展现数字1234可以组成多少个三位数
- SAP事务码MM17物料主数据批量维护
- virtualbox+vagrant学习-2(command cli)-16-vagrant snapshot命令
- 单片机c语言存数据,单片机中C语言的数据存储与程序编写
- smartupload 路径不存在_洞悉复杂金融场景,覆盖完备测试路径
- Shiro使用redis作为缓存(解决shiro频繁访问Redis)
- 添加简单的linux内核模块,操作系统实践 第12章-添加最简单的Linux内核模块.ppt
- Sharding-JDBC水平分库(水平数据库分片策略配置)_Sharding-Sphere,Sharding-JDBC分布式_分库分表工作笔记010
- View内容保存为图片
- C#事件-什么是事件
- Android颜色选择器
- 李彦宏能否避免今年两大必要性错误?
- UE4(Unreal Engine4)快捷键
- 计算机网络基础交换机的基本配置实验报告,计算机网络基础实验报告
- 源码安装nginx 1.23.1
- 锂电池的充电电压和电流应该是多少
- 1核2g1m服务器能支持多少人在线访问?
- Altium Designer新手教程
- Article:AI领域2021年度总结与2022年度展望:多模态人工智能起飞、万亿参数模型的爆发、生成模型在音乐电影制作上的进展、Transformer架构正在以一己之力统一AI江湖、AI法律监管
- 天边一朵云-徒手用html生成一朵云,很真的那种