1.自动装箱、拆箱:
自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类。
自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型。
举例:
public static void main(String[] args) { // TODO Auto-generated method stub // 自动装箱拆箱------>封装对象 // 1.5 jvm // Integer i=1;//装箱 // int j=i;//拆箱 List list = new ArrayList();// 无泛型,则为Object对象,需要强制转换 list.add(1);// 自动装箱,此前要用list.add(Integer(1)) list.add(2); list.add(3); Iterator it = list.iterator(); while (it.hasNext()) { int k = (Integer) it.next();// 拆箱 } }
2.增强for循环:
增强for循环只能用在数组、或实现Iterable接口的集合类上。
举例:
public void test2() { List list = new ArrayList(); list.add(1); list.add(2); list.add(3); // 不能改变值,obj指向另一个值而已,没改变list的原值 // 想改变只能用传统方式 for (Object obj : list) { int i = (Integer) obj;// 没有泛型只能强转 System.out.println(i); obj = 10;// obj指向了另外的数据,而不是改变了list里的值! } }
3.可变参数
调用可变参数的方法时, 编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以数组的形式访问可变参数
可变参数只能处于参数列表的最后, 所以一个方法最多只能有一个长度可变的参数
可变参数就看成是数组。
举例:
public static void sum(int ... nums){ //可变参数在用时,当成数组即可 int sum = 0; for(int num : nums){ sum += num; } System.out.println(sum); }
Arrays.asList(T...a)方法:传入多个对象或多个对-象-数-组都可以---->注意如果传入基本类型数组,将把整个数组当作一个对象处理!
举例:
List list = Arrays.asList("aa","bb","cc"); System.out.println(list); String[] str = {"xx","yy","zz"}; list = Arrays.asList(str); System.out.println(list);
传入基本数据类型的情况:
//注意以下代码int数组和Integer数组的不同 int arr[] = {1,2,3}; list = Arrays.asList(arr); System.out.println(list);
(注意这里不能打印[1,2,3])
4.枚举类
?枚举类也是一种特殊形式的Java类。
?枚举类中声明的每一个枚举值代表枚举类的一个实例对象。
?与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的(这点不难理解)。
带抽象方法的枚举:每个内部枚举对象以内部类的方式实现该枚举类
// 带抽象方法的枚举:调用该方法时,返回中国的成绩等级 enum Grade {// 也是一个类 // 为每个可能值(对象)初始化分数,传给其value字段 A("100-90") {// 因为类存在抽象方法,所以在初始化时要实现其抽象方法 public String localeValue() {// 那么调用A的该方法返回"优",这其实是一个匿名内部类(子类)了 return "优"; }//就把ABCDE看成是恰恰在本类内部初始化的对象吧! }, B("89-80") { public String localeValue() { return "良"; } }, C("79-70") { public String localeValue() { return "一般"; } }, D("69-60") { public String localeValue() { return "差"; } }, E("59-0") { public String localeValue() { return "不及格"; } }; private String value;// 封装每个对象对应的分数 // 注意是私有构造函数,外人不可以初始化! private Grade(String value) { this.value = value; } public String getValue() {// 调用枚举对象的value字段获取自定义分数值 return this.value; } public abstract String localeValue(); }
@Test public void test() { print(Grade.B);// 调用枚举类型的B类成绩(不能用Grade g=B的方式初始化,构造函数私有) } public void print(Grade g) {// ABCDE String value = g.getValue();// 调用其方法 String value1 = g.localeValue();// 调用其方法 System.out.println(value); System.out.println(value1); }
5.加载类与反射
Java中有一个Class类用于代表某一个类的字节码。
Class类即然代表某个类的字节码,它当然就要提供加载某个类字节码的方法:forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装
另外两种得到class对象的方式
类名.class
对象.getClass()
public static void main(String[] args) throws ClassNotFoundException { // TODO Auto-generated method stub // 用Class类来加载一个完整名称的类(带完整包名) Class clazz = Class.forName("cn.itcast.reflect.Person");// 保存加载的类的字节码 // 第二种获取字节码的方式 Class clazz1 = new Person().getClass();// new对象也加载类,再通过其方法获取类字节码 // 第三种 Class clazz2 = Person.class; } // 解剖类的构造函数,创建类的对象 @Test public void test1() throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { Class clazz = Class.forName("cn.itcast.reflect.Person");// 类的字节码加载进内存 Constructor c = clazz.getConstructor(null);// 解剖出无参构造函数 Person p = (Person) c.newInstance(null);// 解剖出的构造函数类一定有这个创建对象的方法(调用对应构造函数),返回Object对象,要强转 System.out.println(p.name); // 要在框架里应用,框架里加载类是用配置文件,里面的类名是一个字符串,想加载配置文件里的类名来自动调用类,而你是无法用一个 // 类名字符串来new对象的 // 自动调用,加载类是用配置文件,所以你也无法确知类名,用手动的方式创建对象 // 我们不用做框架,但要知道框架原理,使用框架 // 配置文件一配,框架自动帮我创建出对象,并可以调用各种属性和方法,就是因为框架后台有这样一段代码 }
@Test public void test2() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getConstructor(String.class);// 参数列表是Class对象的一个数组,标识构造函数形参类型,它是Class的实例 Person p = (Person) c.newInstance("dsfsda"); } @Test public void test3() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getConstructor(String.class, int.class);// 参数列表是Class对象的一个数组,标识构造函数形参类型 Person p = (Person) c.newInstance("fsfs", 12); System.out.println(p.name); }
@Test public void test4() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getDeclaredConstructor(List.class);// private类型的构造函数,而getConstructor只能得到public类型 c.setAccessible(true);// <strong>报错,私有的方法不能在外部访问,用暴力反射,强制可以访问</strong> Person p = (Person) c.newInstance(new ArrayList());// 传参 } // 创建对象的另外一种途径:等效于test1 @Test public void test5() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person");// 获取类的字节码 Person p = (Person) clazz.newInstance();// 其实这个方法内部也是封装<strong>调用了这个类的无-参-构造函数,</strong>所以必须保证定义了无参构造函数 System.out.println(p); }
解析、执行方法:
//Class加载类字节码;Method加载方法字节码(包括参数类型字节码),执行方法,执行某个具体对象的方法 public class Demo3 { @Test public void test1() throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { // 反射类的方法 Person p = new Person(); Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method1 = clazz.getMethod("aa1", null);// 调用无参的方法 method1.invoke(p, null);// 调用方法,要传一个具体对象进去 } @Test public void test2() throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { Person p = new Person(); Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("aa1", String.class, int.class);// 方法名,参数类型(.class文件,因为参数必须要传入对象实体才行!) method.invoke(p, "zfdsl", 38);// 调用某个对象的方法,并传入参数 } @Test public void test3() throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { Person p = new Person(); Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("aa1", String.class, int[].class); // 注意这个调用是有返回值的,但需要强转 Class cs[] = (Class[]) method.invoke(p, "aaaa", new int[] { 1, 23 }); System.out.println(cs[0]); } @Test public void test4() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getDeclaredMethod("aa1", InputStream.class); // 私有方法是可以获取的,但是要想用对象调用,必须先暴力反射 method.setAccessible(true); method.invoke(p, new FileInputStream("c:\\rt.txt"));// 不能给空参数,否则会认为是调用无参的那个aa1方法,报错 }// 出现什么multiple markers的错误:一是没有导包,二是没抛各种异常,三是创建数组格式错误(大括号包元素!)!!! @Test public void test5() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("aa1", int.class); // 静态方法不需要对象!传入null! method.invoke(null, 23); } // 反射main方法 // 传参时jdk1.5接收可变参数,jdk1.4只接收数组,为了与1.4兼容,1.5也接收数组,方法的原理是拆数组成多个参数(注意如果是多个参数的方法写成可变参数形式不会出问题,1.5会调用可变参数形式而1.4会报错) // 而main方法的参数恰好是一个数组,那么1.5,1.4都采用拆开数组的方式变成多个参数,这样就导致main方法传参错误 // 所以,要把main方法的数组参数再包进一个数组里,这样拆数组就拆出唯一一个数组参数,调用正确! @Test // 不仅是main,还要小心所有接收数组参数的方法!!! public void test6() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("main", String[].class); method.invoke(null, new Object[] { new String[] { "aa", "bb" } });// 静态方法不需要传对象! // 另一种办法:强转,欺骗,不让它解析成数组! method.invoke(null, (Object) new String[] { "aa", "bb" }); } }
反射字段:反射出后,想获取某个对象字段的值,需要强转,如果无法确知类型,调用Field类对象的getType方法
@Test public void test1() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.itcast.reflect.Person"); Field f = clazz.getField("name"); // String name = (String) f.get(p);// 强转,并且要有对象 // System.out.println(name); // 获取字段的值 Object value = f.get(p); // 返回字段类型 Class type = f.getType(); System.out.println(type); // 判断后再强转 if (type.equals(String.class)) { String svalue = (String) value; System.out.println(svalue); } } @Test public void test2() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.itcast.reflect.Person"); Field f = clazz.getDeclaredField("password"); f.setAccessible(true);// 私有的要暴力反射 System.out.println(f.get(p)); }
6.JavaBean属性的意义与内省操作
一个JavaBean:
public class Person {// javabean----------->封装用户数据 private String name; private String password;// 字段--------->只有提供了set或get方法才称作属性 private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAb() {// -----------><strong>这也是属性</strong>--------><strong>这个javabean一共有5个属性,因为Object类中还有一个getClass方法!</strong> return null; } }
内省操作:
//使用内省aip操作bean的属性 public class Demo1 { @Test public void test1() throws Exception { BeanInfo info = Introspector.getBeanInfo(Person.class, Object.class);// 内省其属性,去掉Object的属性 PropertyDescriptor[] pds = info.getPropertyDescriptors();// 属性描述器 for (PropertyDescriptor pd : pds) { System.out.println(pd.getName()); } } @Test // 操作bean的指定属性 public void test2() throws Exception { Person p = new Person(); PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); // 获取属性的写方法 Method method = pd.getWriteMethod(); // 执行此方法 method.invoke(p, 88); Method method1 = pd.getReadMethod(); int a = (Integer) method1.invoke(p, null);// 有返回值,Object对象,强转 System.out.println(a); } // 获取当前操作属性的类型 @Test public void test3() throws Exception { Person p = new Person(); PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); Class c = pd.getPropertyType();// 类型,Class对象 System.out.println(c); } }
7.Dom解析
xml文档:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE 书架 SYSTEM "book.dtd"> <书架> <书> <书名 name="中科大">javaweb开发</书名> <作者>张孝祥</作者> <售价>99.00元</售价> <售价>109.00元</售价> <售价>89.00元</售价></书> <书> <书名>JavaScript网页开发</书名> <作者>张孝祥</作者> <售价>28.00元</售价> </书> <页面作者 个人爱好="上网" 网站职务="页面作者" 联系信息="aaaa"/><!--实际三个属性,还有一个固定属性和一个默认属性--> </书架>
附DTD约束(文档,同一目录下):
<pre name="code" class="html"><!ENTITY bookname "javaweb开发"> <!ELEMENT 书架 (书+,页面作者*)> <!ELEMENT 书 (书名,作者,售价+)> <!ELEMENT 书名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售价 (#PCDATA)> <!ATTLIST 书名 name CDATA #IMPLIED> <!ATTLIST 页面作者 姓名 CDATA #IMPLIED 年龄 CDATA #IMPLIED 联系信息 CDATA #REQUIRED 网站职务 CDATA #FIXED "页面作者" 个人爱好 CDATA "上网" >
DOM解析:输出所有节点名(递归)
@Test public void read() throws ParserConfigurationException, SAXException, IOException{ DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document document=builder.parse("src/book.xml"); //得到根节点------->都是Node类型 //注意不要导错包!技巧是导错了一定伴随强转,导了包还需要强转就是导错包了! Node root=document.getElementsByTagName("书架").item(0); //调用递归方法,遍历、打印所有子孙节点名称 list(root); } private void list(Node node){ //先打印此节点名称 System.out.println(node.getNodeName()); NodeList list=node.getChildNodes(); for(int i=0;i<list.getLength();i++){ Node child=list.item(i); //以子节点为参数调用自身 list(child); } }
结果:
书架
#text
书
#text
书名
#text
#text
作者
#text
#text
售价
#text
#text
售价
#text
#text
售价
#text
#text
书
#text
书名
#text
#text
作者
#text
#text
售价
#text
#text
#text
页面作者
#comment
#text
注意:这里不同行之间的空格和换行也被当作了text节点对象!!由于在XML中,空格和换行都作为原始内容被处理,所以,在编写XML文件时,使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变。
如果只想打印所有标签,则加上判断:
private void list(Node node){ //先打印此节点名称 if(node instanceof Element){ System.out.println(node.getNodeName()); } NodeList list=node.getChildNodes(); for(int i=0;i<list.getLength();i++){ Node child=list.item(i); //以子节点为参数调用自身 list(child); } }
结果:
书架
书
书名
作者
售价
售价
售价
书
书名
作者
售价
页面作者
解析标签属性:用Element对象
@Test public void read1() throws ParserConfigurationException, SAXException, IOException{ DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document document=builder.parse("src/book.xml"); //知道它是标签,才强转成标签 Element bookname=(Element)document.getElementsByTagName("书名").item(0); String value=bookname.getAttribute("name"); System.out.println(value); }
结果:
中科大
添加节点:要把Document对象重写写入xml文档
Transformer类和DocumentBuilder一样,构造方法都是被保护的,需要通过工厂类实例化对象。
例子:
@Test public void add() throws ParserConfigurationException, SAXException, IOException, TransformerException{ DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document document=builder.parse("src/book.xml"); //创建节点 Element price=document.createElement("售价"); price.setTextContent("59.00元"); //挂到第一本书 Element book=(Element)document.getElementsByTagName("书").item(0); book.appendChild(price); //把更新后的内存数据写回xml文档 TransformerFactory tffactory=TransformerFactory.newInstance(); Transformer tf=tffactory.newTransformer(); tf.transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml"))); }
@Test //向指定位置插入 public void add2() throws ParserConfigurationException, SAXException, IOException, TransformerException{ DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document document=builder.parse("src/book.xml"); //创建节点 Element price=document.createElement("售价"); price.setTextContent("1009.00元"); //得到参考节点 Element refNode=(Element)document.getElementsByTagName("售价").item(0); //得到要挂崽的节点 Element book=(Element)document.getElementsByTagName("书").item(0); //向指定位置插入 book.insertBefore(price, refNode); //把更新后的内存数据写回xml文档 TransformerFactory tffactory=TransformerFactory.newInstance(); Transformer tf=tffactory.newTransformer(); tf.transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml"))); }
删除售价节点所在的书节点:
@Test //删除节点 public void delete() throws ParserConfigurationException, SAXException, IOException, TransformerException{ DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document document=builder.parse("src/book.xml"); //得到要删除的节点 Element e=(Element)document.getElementsByTagName("售价").item(0); //得到爷爷删除爸爸 //以此类推,如果上溯到document节点则可以将整个文档内容删除(已测试过) e.getParentNode().getParentNode().removeChild(e.getParentNode()); //把更新后的内存数据写回xml文档 TransformerFactory tffactory=TransformerFactory.newInstance(); Transformer tf=tffactory.newTransformer(); tf.transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml"))); }
得到、更新内容,属性(类推,从略):getTextContent,setTextContent,getAttribute,setAttribute---------->分别是Node和Element的方法
xfd