[Java]阶段性知识点技术总结

Posted 晚起的男孩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java]阶段性知识点技术总结相关的知识,希望对你有一定的参考价值。

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

以上是关于[Java]阶段性知识点技术总结的主要内容,如果未能解决你的问题,请参考以下文章

Java自动装箱与拆箱

java-装箱和拆箱

如何理解Java中的自动拆箱和自动装箱?

如何理解Java中的自动拆箱和自动装箱?

装箱和拆箱---JAVA基础篇

Java基础 -- 字符串类(StringStringBufferStringBuilder)自动装箱与拆箱