Java大全(二)

集合

  • Java集合框架:
      		List接口:(不唯一、有序)
      			ArrayList、LinkedList
      		Set:(唯一、无序)
      			HashSet、TreeSet
      		Map:(键唯一,值不唯一)
      			HashMap、TreeMap
    

1.ArryList与LinkedList

  • ArryList与LinkedList是List接口的实现类,List接口存储一组不唯一,有序(插入顺序是有序的)的对象
    
    例如
     0	  	 1		   2		 3 	     4
    aaa		 bb		   cc		aaa		 cc
    
    
    ArryList实现了长度可变的数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高
    LinkedList采用链表存储方式,插入删除元素时效率比较高
    

1.1 ArryList类常用方法

		使用一个类的方法时,一定要去看此类的构造方法(必须的)
		    
  		boolean add(Object o)	 
  					在列表的末尾顺序添加元素,起始索引位置从0开始
  		void add(int index,Object o)  
  					在指定的索引位置添加元素。索引位置必须介于0和列表中元素个数之间
  		int size()  
  					返回列表中的元素个数
  		Object get(int index)  
  					返回指定索引位置处的元素。取出元素是Object类型,使用前需要进行强制类型转换
  		boolean remove(Object o)
  					从列表中删除元素
  		Object remove(int index)
  					从列表中删除指定位置元素,起始索引位置从0开始
  		boolean contains(Object o)
  					判断列表中是否存在指定元素

1.2 ArryList各种方法用法例子

	import java.util.ArrayList;
		public class Test {
			/*
			 * 可以存储各类新闻标题(包含ID、名称、创建者) 可以获取新闻标题的总数 可以逐条打印每条新闻标题的名称
			 */
			public static void main(String[] args) {
				// 创建3新闻标题类对象
				NewsTitle nt1 = new NewsTitle(1001, "合肥新站区和肥西各新增1例新冠肺炎感染者", "合肥日报");
				NewsTitle nt2 = new NewsTitle(1002, "合肥今日有暴雨,局部地区特大暴雨", "张三");
				NewsTitle nt3 = new NewsTitle(1003, "震惊,程序员每天竟然喜欢干这件事", "李四");
				NewsTitle nt4 = new NewsTitle(1004, "安徽泗县昨日新增新冠肺炎无症状感染者23例", "安徽日报");
		
				// 准备集合容器,调用ArrayList类的无参构造方法,创建一个默认长度为10的集合容器
				ArrayList al = new ArrayList();
		
				// 将创建的新闻标题对象存储到al集合中
				al.add(nt1);
				al.add(nt3);
				al.add(nt2);
		
				// 获取新闻标题的总数----》获取集合中元素的个数
				//int size():返回列表中的元素个数
				int size = al.size();
				System.out.println("集合中元素的个数:" + size);
		
				// 可以逐条打印每条新闻标题的名称
				//Object get(int index):返回指定索引位置处的元素。取出的元素是Object类型,使用前需要进行强制类型转换
				// Object obj1 =al.get(0);
				// NewsTitle newsTile1 = (NewsTitle)obj1;
				// System.out.println(newsTile1.getName());
				//
				// Object obj2 =al.get(1);
				// NewsTitle newsTile2 = (NewsTitle)obj2;
				// System.out.println(newsTile2.getName());
				//
				// Object obj3 =al.get(2);
				// NewsTitle newsTile3 = (NewsTitle)obj3;
				// System.out.println(newsTile3.getName());
		
				for (int i = 0; i < al.size(); i++) {
					Object obj = al.get(i);
					NewsTitle newsTile = (NewsTitle) obj;
					System.out.println(newsTile.getId()+"--"+newsTile.getName());
				}
				
				//void add(int index,Object o):在指定的索引位置添加元素。索引位置必须介于0和列表中元素个数之间
				al.add(0, nt4);
				NewsTitle news =(NewsTitle)al.get(0);
				System.out.println(news);
				
				//boolean contains(Object o):判断列表中是否存在指定元素,如果集合中存在你要找的元素,返回true,否则返回false
				boolean result1 =al.contains(nt3);
				System.out.println("集合中存在你要找的元素nt3:"+result1);
				
				//boolean remove(Object o):从列表中删除元素,删除成功返回true,删除失败返回false
				
				boolean result2 =al.remove(nt4);
				System.out.println("删除元素成功:"+result2);
				for (int i = 0; i < al.size(); i++) {
					Object obj = al.get(i);
					NewsTitle newsTile = (NewsTitle) obj;
					System.out.println(newsTile.getId()+"--"+newsTile.getName());
				}
				System.out.println("---------------");
				
				//Object remove(int index):从列表中删除指定位置元素,起始索引位置从0开始
				Object obj =al.remove(0);
				NewsTitle newsTile = (NewsTitle) obj;
				System.out.println(newsTile);
				System.out.println("--------------");
				for (int i = 0; i < al.size(); i++) {
					Object obje = al.get(i);
					NewsTitle newsTilee = (NewsTitle) obje;
					System.out.println(newsTilee.getId()+"--"+newsTilee.getName());
				}
				
				//clear():清空集合中的所有元素
				//al.clear();
				//System.out.println(al.size());
				//isEmpty():如果此列表中没有元素,则返回 true
				//System.out.println(al.isEmpty());
				
				System.out.println("--------------");
				
				//toArray():将集合变成数组
				Object[] objs  =al.toArray();
				for (int i = 0; i < objs.length; i++) {
					System.out.println(objs[i]);
				}
						
				System.out.println("--------------");
				
				//iterator():迭代器(遍历),将集合中的元素“转移”到了迭代器这么一个容器中,接下来对迭代器容器进行遍历
				Iterator it =al.iterator();  //iterator()方法是
				//遍历it这个容器,先使用hasNext()方法判断容器中是否有元素,有,使用next()方法取出,然后再判断,如果有,就取出元素,继续再判断,有,继续取出
				//it.hasNext():判断迭代器中是否有元素,如果有元素返回true
				while(it.hasNext()){
					//取出元素
					Object object =it.next(); //多态
					System.out.println(object);  
				}
				
				System.out.println("--------------------------------------");
				for(Object ob:al){
					//子类重写了Object中的toString()方法,上一行代码是向上转型(多态),子类引用指向父类,所以这里的object在println()内部调用的是重写的toString()方法
					System.out.println(ob);
				}
			}
		}

1.3 LinkedList类常用方法

  • LinkedList类是List接口的一个具体实现类,它是用于创建链表数据结构,当插入或删除元素时,性能会更好
    
    void  addFirst(Object o) 	在列表的首部添加元素
    Object getFirst() 			返回列表中的第一个元素
    Object  getLast()			返回列表中的最后一个元素
    Object  removeFirst()	 	删除并返回删除的这个元素
    Object  removeLast()		删除并返回列表中的最后一个元素
    
  • 例子
    
    public class Test {
      	/*
      	 * 新闻管理系统,需求如下 可以添加头条新闻标题 获取头条和最末条新闻标题 可以删除末条新闻标题
      	 */
      	public static void main(String[] args) {
      		// 准备集合中的内容,创建3个NewsTitle类对象
      		NewsTitle nt1 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
      		NewsTitle nt2 = new NewsTitle(1002, "合肥将变成一个没有传销的城市", "李四");
      		NewsTitle nt3 = new NewsTitle(1003, "合肥比亚迪即将建成开厂", "王五");
      		NewsTitle nt4 = new NewsTitle(1004, "大湖名城,创新高低", "赵六");
      		NewsTitle nt5 = new NewsTitle(1005, "大湖名城,创新高低", "孙七");
      		
      		//准备容器,创建LinkedList对象
      		LinkedList list = new LinkedList();
      		list.add(nt1);
      		list.add(nt2);
      		list.add(nt3);
      		list.addLast(nt5);
      		list.addFirst(nt4);
      		
      		
      		for (int i = 0; i < list.size(); i++) {
      			System.out.println(list.get(i));
      		}
      		
      		System.out.println("-------------获取元素-------------");
      		
      		System.out.println(list.getFirst());
      		System.out.println(list.getLast());
      		
      		System.out.println("-------------删除元素--------------");
      		System.out.println(list.removeFirst());
      		System.out.println(list.removeLast());
      		
      		System.out.println("--------------删除元素后进行遍历-------------");
      		for (Object object : list) {
      			System.out.println(object);
      		}
      
      	}
      }
      
      输出结果
      			NewsTitle [id=1004, name=大湖名城,创新高低, author=赵六]
      			NewsTitle [id=1001, name=Java中还有这么神奇的事情, author=张三]
      			NewsTitle [id=1002, name=合肥将变成一个没有传销的城市, author=李四]
      			NewsTitle [id=1003, name=合肥比亚迪即将建成开厂, author=王五]
      			NewsTitle [id=1005, name=大湖名城,创新高低, author=孙七]
      			-------------获取元素-------------
      			NewsTitle [id=1004, name=大湖名城,创新高低, author=赵六]
      			NewsTitle [id=1005, name=大湖名城,创新高低, author=孙七]
      			-------------删除元素--------------
      			NewsTitle [id=1004, name=大湖名城,创新高低, author=赵六]
      			NewsTitle [id=1005, name=大湖名城,创新高低, author=孙七]
      			--------------删除元素后进行遍历-------------
      			NewsTitle [id=1001, name=Java中还有这么神奇的事情, author=张三]
      			NewsTitle [id=1002, name=合肥将变成一个没有传销的城市, author=李四]
      			NewsTitle [id=1003, name=合肥比亚迪即将建成开厂, author=王五]
    

2.HashSet

2.1 HashSet类中的方法

  • boolean add(E e)
    int size()
    Iterator iterator()   返回此集合中元素的迭代器,元素没有特定的顺序返回。 
    无get()方法
    	  
    注:
    	Iterator接口中的方法
      			 boolean hasNext()
      			 E next()
        迭代器作用
        		是用来访问容器(用来保存元素的数据结构)中的元素,所以使用迭代器,我们就可以访问容器中里面的元素
    
  • HashSet是Set接口常用的实现类 ,set集合是无序的,所以不能使用get(下标)获取元素
    
    如何遍历Set集合呢?
    方法一:
    		通过获取迭代器Iterator实现遍历
    		Collection接口的iterator()方法
    		
    		Iterator接口的方法
    				boolean hasNext()  判断是否存在另一个可访问的元素
    				Object next()   返回要访问的下一个元素(因为这不是指向第一个元素,而是先指向的是空元素,所以访问的是下一个元素)
    方法二:
    		增强for循环
    
  • 例子
      	public class Test {
      	
      		public static void main(String[] args) {
      			//准备数据:创建NewsTitle对象
      			NewsTitle nt1 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
      			NewsTitle nt2 = new NewsTitle(1002, "合肥将变成一个没有传销的城市", "李四");
      			NewsTitle nt3 = new NewsTitle(1003, "合肥比亚迪即将建成开厂", "王五");
      			NewsTitle nt4 = new NewsTitle(1004, "大湖名城,创新高低", "赵六");
      			NewsTitle nt5 = new NewsTitle(1005, "大湖名城,创新高低", "孙七");
      			
      			//准备容器
      			HashSet hs = new HashSet();
      			hs.add(nt1);
      			hs.add(nt2);
      			hs.add(nt3);
      			hs.add(nt4);
      			hs.add(nt5);
      			hs.add(nt1);
      			hs.add(nt1);
      			System.out.println(hs.size());//5  因为他唯一,当重复了就不再往里加了
      			
      			for (Object object : hs) {   //因为set是无序的,所以每一次遍历都会输出的顺序不同(不考虑内存缓存问题)
      				System.out.println(object);
      			}
      			
      			System.out.println("-------------------");
      			
      			//set集合是无序的,所以不能使用get(下标)获取元素
      			//hs.get(0);
      			
      			Iterator it = hs.iterator();
      			while(it.hasNext()){
      				Object obj =it.next();
      				NewsTitle nt = (NewsTitle)obj;
      				System.out.println(nt);
      			}
      		
      		}
      	
      	}
    
  • 特例
      public class Demo {
    
      		public static void main(String[] args) {
      			Set set = new HashSet();
      			String s1 = new String("java");
      			String s2 = s1;
      			String s3 = new String("JAVA");
      			
      			NewsTitle nt1 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
      			NewsTitle nt2 = new NewsTitle(1001, "Java中还有这么神奇的事情", "张三");
      			
      			set.add(nt1);
      			set.add(nt2);
      			System.out.println(set.size());//2		//new了两个不同的对象,回头搞一下String类和普通类  堆内存和栈内存存放方式
      			
      		
      			set.add(s1);
      			set.add(s2);
      			set.add(s3);
      			System.out.println(set.size());//4
      			
      			
      	
      		}
      	
      	}
    

3.HashMap

  • 例子
      public class Test {
      		/*
      		 * 需求说明
      		 * 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。
      		 * 请实现通过英文名称,获得该学员对象的详细信息
      		 * 学员属性包括姓名以及性别
      	
      		 */
      		public static void main(String[] args) {
      			//创建学生对象
      			Student stu1 = new Student("张三", "男");   //已经重写了toString()方法
      			Student stu2 = new Student("李四", "男");
      			Student stu3 = new Student("如花", "女");
      			
      			//创建HashMap集合对象
      			HashMap hm = new HashMap();
      			
      			//将学生对象添加到集合中
      			hm.put("jack", stu1);
      			hm.put("tom", stu2);
      			hm.put("rose", stu3);
      			
      			Object obj = hm.get("jack");
      			Student stu = (Student)obj;
      			System.out.println("Jack对应的学员信息为:姓名:"+stu.getName()+",性别:"+stu.getGender());
      	
      			System.out.println("--------------------------");
      			
      			//使用键值对的方式遍历输出所有学员的姓名和性别
      			Set set =hm.entrySet();
      			for(Object object:set){
      				Map.Entry me = (Map.Entry)object;
      				//获取键值对的键
      				Object obj1 = me.getKey();
      				String key = (String)obj1;
      				//获取键值对的值
      				Object obj2=me.getValue();
      				Student student = (Student)obj2;
      				System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
      			}	
      		}
      	}
    
  • 使用键值对方式遍历输出
      		Set set = (new HashMap).entrySet();
      		for(Object obj : set){
      			Map.Entry me =(Map.Entry)obj;
      			Object obj1 =me.getKey();		//获取键值对的健(重写toString()方法,可以直接输出obj1)
      			Object obj2 =me.getValue();    //获取键值对的值
      		}
      
    例子
    public class Test {
      	/*
      	 * 需求说明
      	 * 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。
      	 * 请实现通过英文名称,获得该学员对象的详细信息
      	 * 学员属性包括姓名以及性别
      
      	 */
      	public static void main(String[] args) {
      		//创建学生对象
      		Student stu1 = new Student("张三", "男");
      		Student stu2 = new Student("李四", "男");
      		Student stu3 = new Student("如花", "女");
      		
      		//创建HashMap集合对象
      		HashMap hm = new HashMap();
      		
      		//将学生对象添加到集合中
      		hm.put("jack", stu1);
      		hm.put("tom", stu2);
      		hm.put("rose", stu3);
      		
      		Object obj = hm.get("jack");
      		Student stu = (Student)obj;
      		System.out.println("Jack对应的学员信息为:姓名:"+stu.getName()+",性别:"+stu.getGender());
      
      		System.out.println("--------------------------");
      		
      		//使用键值对的方式遍历输出所有学员的姓名和性别
      		Set set =hm.entrySet();
      		for(Object object:set){
      			Map.Entry me = (Map.Entry)object;
      			//获取键值对的键
      			Object obj1 = me.getKey();
      			String key = (String)obj1;
      			//获取键值对的值
      			Object obj2=me.getValue();
      			Student student = (Student)obj2;
      			System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
      		}
      	}
      
      }
    

3.1 HashMap常用方法(加上泛型)

  • public V put(K key, V value){}
    public V remove(Object key) {}
    public int size() {}
    public boolean containsKey(Object key) {}
    	在HashMap集合中,键值对的健若是有,则返回true	  
    public boolean containsValue(Object value) {}
    	在HashMap集合中,键值对的值若是有,则返回true
    public Collection values() {}    
    	返回的是获取值的集合
    	
    public Set keySet() {}  						返回的是键值对的集合
    public Set> entrySet() {}		返回的是将集合中的键值对全部取出来存储到Set集合(我觉得是把引用赋值给Set集合),目的是为了下一步可以调用iterator()方法,因为是在HashMap内部的类实现了iterator方法,HashMap没有办法直接调用这个方法
    	返回的是获取的是键值对的健的集合(可以直接进行打印,打印出的是健的集合)
    	这里需要注意一点,那么要分别打印呢?(需要进源码看一下....)
      		  	step overF6  不进入内部,只执行自己写的代码
      		  	step overF5  进入内部,执行所有需要执行的代码
      		  	
      		  	(HashMap类里面有一个内部类KeySet,而KeySet有继承了AbstractSet)	  		
      		    public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
      				{
      					............
      				     private final class KeySet extends AbstractSet {
      					        public Iterator iterator() {
      					            return newKeyIterator();
      					        }
      				        	.........
      				     }
      				} 
      				
      			(Abstract类实现了Set接口,所以重写了Set接口中的iterator()方法,但这个抽象类没有重写iterrator()方法,又被HashMap继承了,所以是HashMap类实现了Set接口中的iterator()方法)
      	   		public abstract class AbstractSet extends AbstractCollection implements Set {
      	   		}
      	   		
      	   		阿西吧..........
      	   		看下面的例子,就是为了看懂下面两行代码 		
      		   		Set keys2 = hm.keySet();
      				Iterator it = keys2.iterator();   //疑惑就在为什么Set类型的接口可以调用iterator,原因就是HashMap绕了一圈实现了Set接口
      	   		
    
    
    例子
      	 public class Test {
      		public static void main(String[] args) {
      			//准备键值对容器用来存储键值对
      			HashMap hm = new HashMap();
      			
      			//向集合中存储数据
      			hm.put("CN", "中华人民共和国");
      			hm.put("RU","俄罗斯联邦");
      			hm.put("US", "美利坚合众国");
      			hm.put("JP", "日本");
      			
      			System.out.println(hm.size());
      			
      			String str1 =hm.get("CN");
      			System.out.println(str1);
      			
      			//Object remove(key):根据键来删除键值对,返回值是键对应的值
      			String str2=hm.remove("JP");
      			System.out.println(str2);
      			System.out.println(hm.size());
      			
      			System.out.println(hm.containsKey("CN"));//true
      			System.out.println(hm.containsKey("JP"));//false
      			
      			System.out.println(hm.containsValue("中华人民共和国"));//true
      			
      			//keySet():返回集合中所有键值对的键的集合
      			Set keys=hm.keySet();
      			for (String object : keys) {
      				String key = object;
      				String obj =hm.get(key);
      				String value = obj;
      				System.out.println(key+"---"+value);
      			}
      			
      			System.out.println("--------------------");
      			
      			//Collection values():获取值得集合
      			Collection coll = hm.values();
      			for (String object : coll) {
      				String value = object;
      				System.out.println(value);
      			}
      			
      			System.out.println("--------------------");
      			
      			//获取键的集合
      			Set keys2 = hm.keySet();
      	
      			Iterator it = keys2.iterator();  
      			
      			while(it.hasNext()){
      				String key =it.next();
      				String value =hm.get(key);
      				System.out.println(key+"---"+value);
      			}
      			
      			System.out.println("--------------------");
      			
      			//使用键值对的方式取出集合中的键值对
      			Set> keyValues = hm.entrySet(); //将集合中的键值对全部取出来存储到Set集合
      			Iterator> iterator =keyValues.iterator();//将Set集合中的元素存储到迭代器中
      			while(iterator.hasNext()){
      				Entry me =iterator.next();//使用next()方法获取迭代器中的元素
      				String key = me.getKey();//键值对类型对象调用getKey()方法可以获取键值对的键
      				String value=me.getValue();键值对类型对象调用getValue()方法可以获取键值对的值
      				System.out.println(key+"~~~~~"+value);
      			}
      	
      		}
      	
      	}
    

3.2 泛型

  • 将对象的类型作为参数,指定到其它类或者方法上,从而保证类型转换的安全性和稳定性
    
    Java大全(二)_第1张图片
  • 泛型集合可以约束集合内的元素类型
    典型泛型集合ArryList、HashMap  对于表示该泛型集合中的元素类型,泛型集合中的数据不再转换为Object
    
    例子
      	  public class Test {
      
      	/*
      	 * 需求说明
      	 * 学员应聘至外企工作,每个学员都会有一个英文名称,对应该学员对象。
      	 * 请实现通过英文名称,获得该学员对象的详细信息
      	 * 学员属性包括姓名以及性别
      
      	 */
      	public static void main(String[] args) {
      		//创建学生对象
      		Student stu1 = new Student("张三", "男");
      		Student stu2 = new Student("李四", "男");
      		Student stu3 = new Student("如花", "女");
      		
      		//创建HashMap集合对象
      		HashMap hm = new HashMap();
      		
      		//将学生对象添加到集合中
      		hm.put("jack", stu1);
      		hm.put("tom", stu2);
      		hm.put("rose", stu3);
      		
      		Student stu = hm.get("jack");
      		System.out.println("Jack对应的学员信息为:姓名:"+stu.getName()+",性别:"+stu.getGender());
      
      		System.out.println("--------------------------");
      		
      		Set> set =hm.entrySet();
      
    //使用迭代器遍历输出所有学员的姓名和性别
      		Iterator>  iterator= set.iterator();
      		while(iterator.hasNext()){
      			Entry me = iterator.next();
      			System.out.println(me.getKey()+"-------"+me.getValue().getName()+"----------"+me.getValue().getGender());
      		}
      
      		System.out.println("---------------------------");
      
    //使用键值对的方式遍历输出所有学员的姓名和性别
      		for(Map.Entry me:set){
      			//获取键值对的键
      			String key = me.getKey();
      			//获取键值对的值
      			Student student=me.getValue();
      			System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
      		}
      	}
      }
    

3.3 加强for循环

  •  	public static void main(String[] args) {
    
    //arr
      		 int arr[]={1,2,3,4,5,6};
      		 for(int i : arr){
      		        System.out.println(i);
      		 }
      	     
    //string
      	     String s [] =  {"hello","world","java"};
      	     for(String i : s){
      		        System.out.println(i);
      		  }
      	     
    //list
      	     List list = new ArrayList();
      	     list.add("hello");
      		 list.add("world");
      		 list.add("java");
      		 for(String i : list){
      		        System.out.println(i);
      		 }
    
    //使用键值对的方式遍历输出所有学员的姓名和性别
      	 	HashMap hm = new HashMap();
      	 	Student stu1 = new Student("张三", "男");
      	 	hm.put("jack", stu1);
      	 	Set> set =hm.entrySet();
      		for(Map.Entry me:set){
      			//获取键值对的键
      			String key = me.getKey();
      			//获取键值对的值
      			Student student=me.getValue();
      			System.out.println(key+"对应的学员姓名:"+student.getName()+",性别为:"+student.getGender());
      		}
       }
       
    Map.Entry<>  查一下资料,了解一下
    
    这些都是集合或者数组的'引用'进行for循环的
    

3.4 InstanceOf用法

  • instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例。
    类型判断关键字。a  instanceof b:判断a对象是不是b类型。这儿判断的时候,如果返回此语句已经返回ture,那么把b替换成b的父类型,也会是true
    
    例子		
      	class Animal{
      	    String name;
      	
      	    Animal(String name){
      	        this.name = name;
      	    }
      	}
      	
      	public class Dog extends Animal{
      	    Dog(String name){
      	        super(name);
      	    }
      	    public  static void main(String[] msg){
      	        Dog gg1 = new Dog("小白");
      	        Animal gg2 = new Animal("旺财");
      	        Animal gg3 = new Dog("狗蛋");
      	        System.out.println(gg1 instanceof Dog); //True本类对象是本类的实例
      	        System.out.println(gg1 instanceof Animal); //True子类对象是父类的实例
      	        System.out.println(gg2 instanceof Dog); //false父类对象不是子类的实例
      	        //System.out.println(Dog instanceof gg2); //编译错误,第一个关键字是引用类型,不可以是类
      	        System.out.println(gg3 instanceof Dog); //True父类引用指向子类对象,该对象仍是子类的实例
      	    }
      	}
    

4.枚举

  •  枚举是指由一组固定的常量组成的类型
    
      public enum Genders {
      Male,Female
      }
    
    (注意下面gender的类型是枚举类型)
      public class Student{
      
      	private String name;
      	private Genders gender;
      	public String getName() {
      		return name;
      	}
      	public void setName(String name) {
      		this.name = name;
      	}
      	public Genders getGender() {
      		return gender;
      	}
      	public void setGender(Genders gender) {
      		this.gender = gender;
      	}
     }
    
      (注意:stu.setGender(Genders.Male);  该方法里只能传在Gender中已经定义好的)
      public class StudentTest {
      	public static void main(String[] args) {
      		
      		Student stu = new Student();
      		stu.setName("张三");
      		stu.setGender(Genders.Male);
      
      		System.out.println(stu.getName()+"--"+stu.getGender());
      		
      		System.out.println(Math.log10(10));
      	}
      }
    

5.Java API

5.1 包装类

  • 包装类是把基本数据类型转换为对象,每个基本类型在java.lang包中都有一个相应的包装类
    
  • 包装类的关系图
    

Java大全(二)_第2张图片

  包装类的作用
			  提供了一系列使用的方法
			  集合不允许存放基本数据类型数据,存放数字时,要用包装类型
			  
 	  

  包装类的构造方法
  			所有包装类都可将与之对应的基本数据类型作为参数来构造它们的实例
  			public Type(type value){    //这是8大类型的构造方法,没有无参构造
					this.value  = value
				}
			例如
  			public Integer(int value) {
				    this.value = value;
		 	    }
		 	    
  除Character类外,其它包装可将一个字符串作为参数构造它们的实例
  例如
  		Integer i = new Integer("123");
注意:
		Boolean类型构造方法参数为String类型时,若该字符串内容为true(不考虑大小写),则该Boolean对象表示true,否则表示false
		Integer i = new Integer("abc"),这个虽然编译不报错,但是运行时会抛出异常,numberformatexception表示数字格式化异常
		Byte b = new Byte(1); 与 Short s = new Short((short) 1);必须要进行强制类型转换,因为,你传过去的是int类型的数据,构造函数接收的是小于int类型的数据
	

	包装类型的常用方法
  	XXXValue():包装类型转换成基本类型
  	例子
		  	Integer in = new Integer(25);
		  	int i =	in.intValue();
		  	
	toString():以字符串形式返回包装对象表示的基本类型数据(基本类型->字符串)
	例子
			String sex = Character.toString('男');
			String str = Boolean.toString(true);
			Integer inte = new Integer(100);
			String str2 = inte.toString();

	parseXXX():把字符串转换为相应的基本数据类型数据(Character除外,并且字符串里面的内容要能够转换为数字,否则会报异常)(字符串->基本类型)
			byte num2 = Byte.parseByte("123");
			System.out.println(num2);
			boolean result = Boolean.parseBoolean("TruE");
			System.out.println(result);
			
	valueOf():所有包装类都有如下方法(基本类型->包装类) public static Type valueOf(type value)
			byte byte2 = 10;
			Byte byte3 = Byte.valueOf(byte2);
			Byte byte4 = Byte.valueOf((byte)1);
			Character cha = Character.valueOf('女');
    除Character类外,其他包装类都有如下方法(字符串->包装类)public static Type valueOf(String s)
			Byte byte5 = Byte.valueOf("123");
			// Character.valueOf("a");   报错

5.2 Collections与Collection

  •   Collections是一个工具类。工具类是工具,就像Math,Arrays类一样,他是一种工具,集成了很多特定的功能。
      比如排序,拷贝,替换,反转等等等功能。工具类不能被实例化。 工具类使用方式:类名.方法名()
      
      总体来说:collection是接口  , collections是工具类
      
      Collections工具类的方法	
      		sort():排序
      		binarySearch():查找
      		max()\min():查找最大\最小值
      		实现一个类的对象之间比较大小,该类要实现Comparable接口,重写compareTo()方法,因为使用sort方法进入内部操作会调用到compartTo方法
      		
      	   ************************
      	   由于例子1中String类已经重写过compartTo方法,而例子2中自己定义的类需要自己实现compareTo方法
    
    例子1(String类已经重写过compartTo方法)
      	public class Demo01 {
      	
      	public static void main(String[] args) {
      			ArrayList al = new ArrayList();
      			
      			al.add("wseurfhu");
      			al.add("dsfsdf");
      			al.add("asdewre");
      			al.add("sdfsf");
      			al.add("afhth");
      			
      			System.out.println("集合排序之前:");
      			for (String string : al) {
      				System.out.println(string);
      			}
      			
      			//Collections.sort():对集合进行排序
      			Collections.sort(al);
      			
      			System.out.println("集合排序后:");
      			for (String string : al) {
      				System.out.println(string);
      			}
      			
      			//int binarySearch(集合名,查找的数据):查找元素,返回查找元素所在的下标,如果查找不到元素,返回一个负值。 注意:使用该方法之前,对先对集合进行升序排序,否则不能保证查询结果的正确性
      			int index = Collections.binarySearch(al, "sdfsfgj");
      			System.out.println(index);
      			
      			//max()/min():求集合中的最大值最小值
      			String max = Collections.max(al);
      			System.out.println(max);
      			String min = Collections.min(al);
      			System.out.println(min);
      			
      			
      			Collections.reverse(al);	
      			System.out.println("集合元素反转之后:");
      			Iterator it=al.iterator();
      			while(it.hasNext()){
      				String str = it.next();
      				System.out.println(str);
      			}
      		}
      	}
    
    
    例子2 (实现Comparable接口)
    
      		public class Student implements Comparable{
      			private int number=0; 			//学号
      			private String name=""; 		//学生姓名
      			private String gender="";	 	//性别
      			public int getNumber(){
      				return number;
      			}
      			public void setNumber(int number){
      				this.number=number;
      			}
      			public String getName(){
      				return name;
      			}
      			public void setName(String name){
      				this.name=name;
      			}
      			public String getGender(){
      				return gender;
      			}
      			public void setGender(String gender){
      				this.gender=gender;
      			}
      			
      			public int compareTo(Object obj){
      				Student student=(Student)obj;
      				if(this.number==student.number){  
      					return 0;			//如果学号相同,那么两者就是相等的
      				}else if(this.number>student.getNumber()){ 
      					return 1;			//如果这个学生的学号大于传入学生的学号
      				}else{ 
      					return -1;			//如果这个学生的学号小于传入学生的学号
      				}
      			}
      		}
    
    
      	import java.util.ArrayList;
      	import java.util.Collections;
      	import java.util.Iterator;	 
      	public class Test {
      		public static void main(String[] args) {
      			Student student1=new Student();
      			student1.setNumber(5);
      			Student student2=new Student();
      			student2.setNumber(2);
      			Student student3=new Student();
      			student3.setNumber(1);
      			Student student4=new Student();
      			student4.setNumber(4);
      			ArrayList list=new ArrayList();
      			list.add(student1);
      			list.add(student2);
      			list.add(student3);
      			list.add(student4);
      			System.out.println("-------排序前-------");
      			Iterator iterator=list.iterator();
      			while(iterator.hasNext()){
      				Student stu=iterator.next();
      				System.out.println(stu.getNumber());
      			}
      			//使用Collections的sort方法对list进行排序
      			System.out.println("-------排序后-------");
      			Collections.sort(list); 
      			iterator=list.iterator();
      			while(iterator.hasNext()){
      				Student stu=iterator.next();
      				System.out.println(stu.getNumber());
      			} 
      	 
      		}
      	}
    

5.3 拆箱和装箱

public class Demo04 {

	public static void main(String[] args) {
		// 装箱和拆箱

		byte byte1 = 10;
		Byte byte2 = new Byte(byte1);
		Byte byte3 = Byte.valueOf(byte1);

		// 装箱:直接将基本数据类型赋值给了包装类对象
		Byte byte4 = byte1;
		System.out.println(byte4);

		Integer int1 = new Integer(20);
		int int2 = int1.intValue();
		// 拆箱:将包装类对象直接赋值给基本数据类型的变量
		int int3 = int1;
		System.out.println(int3);

		// JDK1.5后,允许基本数据类型和包装类型进行混合数学运算
		Integer num1 = new Integer(100);
		int num2 = 1000;
		int sum = num1 + num2;
		System.out.println(sum);
		Integer sum2 = num1 + num2;
		System.out.println(sum2);
	}
}

5.4 拆箱和装箱面试题

		Integer i1 = 100;
		Integer i2 = 100;
		Integer i3 = 200;
		Integer i4 = 200;
		Integer i5 = new Integer(127);
		Integer i6 = new Integer(127);
		System.out.println(i5 == i6);//false
		System.out.println(i5.equals(i6));//true
		System.out.println(i1==i2);//true
		System.out.println(i3==i4);//false
		
		Float f1 = 20F;
		Float f2 = 20F;
		System.out.println(f1 == f2);   //false
		
		Double i1 = 100.0;
		Double i2 = 100.0;
		Double i3 = 200.0;
		Double i4 = 200.0;
		System.out.println(i1==i2);//false
		System.out.println(i3==i4);//false
		System.out.println(i3.equals(i4)); //true
		
		//在Boolean中定义了2个静态成员属性
		Boolean i1 = false;
		Boolean i2 = false;
		Boolean i3 = true;
		Boolean i4 = true;
		System.out.println(i1==i2);//true
		System.out.println(i3==i4);//true
		
		Integer a = 1;
		Integer b = 2;
		Integer c = 3;
		Integer d = 3;
		Integer e = 321;
		Integer f = 321;
		Long g = 3L;
		Long h = 2L;
		Long p = 128L;
		Long p1 =128L;
		System.out.println(c==d);//true 比较cache
		System.out.println(e==f);//false 比较引用
		System.out.println(c==(a+b));//true 比较值
		System.out.println(c.equals(a+b));//true 比较值
		System.out.println(g==(a+b));//true //比较值
		System.out.println(g.equals(a+b));//false //比较引用(对于包装器类型,equals方法并不会进行类型转换),
		System.out.println(g==(a+b));  //true
		System.out.println(g.equals(a+h));//true比较引用
		System.out.println(p==p1); //false
		
		Integer  a = 444;
		int b = 444;
		System.out.println(a==b);    //true 比较值 (拆箱)
		System.out.println(a.equals(b));//true比较值

/*
	当给Integer 对象赋一个int值的时候,会调用Integer类的静态方法valueOf。
	简单来说,如果数值的大小在 -128 到 127 之间,那么不会 new 一个新的 Integer 对象,而是直接引用常量池中的Integer对象,
	所以上面的 f1 = = f2 的结果是 true,因为f1 = 100, f2 = 100, 两个值都在-128到127的区间内。而f3 = = f4 的结果为false。
	
	Double与Float类型中的valueOf方法,每次返回都是重新new的对象。
	
	java1.5开始的自动装箱拆箱机制其实是编译时自动完成替换的,装箱阶段自动替换为了valueOf方法,拆箱阶段自动替换为了xxxValue方法
	对于Integer、Short、Byte、Character、Long类型的valueOf方法,参数如果是-128~127之间的值会直接返回内部缓存池中已经存在对象的引用,
	参数是其他范围值则返回新建对象

	对于两边都是包装类型的比较==比较的是引用,equals比较的是值。
	对于两边有一边是表达式(包含算数运算)则==比较的是数值(自动触发拆箱过程),对于包装类型equals方法不会进行类型转换
*/

  • 问:java语句Integeri=1;i+=1;做了哪些事情?
    
    	首先 Integer i = 1; 做了自动装箱(使用 Integer.valueOf() 方法将 int 装箱为 Integer 类型),
    	接着 i += 1; 先将 Integer 类型的 i 自动拆箱成 int(使用Integer.intValue() 方法将 Integer 拆箱为 int),完成加法运行之后的 i 再装箱成 Integer 类型。
    

6.实用类

6.1 Math常用方法

  • 括号里的类型指的是传参对面接收的类型
    Math.random()       随机获取double类型的[0.0,1.0)之间的数
    Math.PI 					返回Π		
    Math.abs(int/long/float/double类型)   返回取绝对值 
    Math.ceil(double类型)  		返回一个比a大的离a最近的整数	
    Math.floor(double类型)      返回一个比a小的并且离a最近的整数	
    Math.round(float/double类型)		返回根据四舍五入的规则
    Math.max(int/long/float/double a,b)		两个数取出最大值	
    Math.min(int/long/float/double a,b)    	两个数取最小值	
    Math.pow(double a,b)					返回a的b次方
    
    例子
      	    double num =Math.random();
      		System.out.println(num);			//0.21315734454875046
      		
      		//随机获取一个[num1,num2]之间的整数
      		//int num = (int)(Math.random()*(num2-num1)+num1)
      
      		System.out.println(Math.PI);  		 //返回Π的值  	3.141592653589793
      		
      		System.out.println(Math.abs(-60));   //取绝对值     	60
      		
      		System.out.println(Math.ceil(3.1)); //ceil(double a) 返回一个比a大的离a最近的整数		4.0
      		
      		System.out.println(Math.floor(3.9)); //Math.floor(double a)  返回一个比a小的并且离a最近的整数		3.0
      			
      		System.out.println(Math.round(3.5));  //Math.round(double a)  根据四舍五入的规则		4
      		
      		System.out.println(Math.max(12, 25));  //两个数取出最大值						25
      		
      		System.out.println(Math.min(2,5));	//两个数取最小值						2
      		
      		System.out.println(Math.pow(2, 5)); //Math.pow(a,b)  返回a的b次方			32.0	
    

6.2 Random常用方法

  •       public boolean nextBoolean() {...}
      				每次运行随机生成true或者false
      	  public int nextInt() {}
      				不带参数的nextInt()会生成所有有效的整数(包含正数,负数,0)
      	  public int nextInt(int n) {}
      	 		    带参的nextInt(int x)则会生成一个范围在0~x(不包含X)内的任意正整数
      	  		  		    
      
      	  
    例子
      		  	Random random1 = new Random();
      			System.out.println(random1);   //java.util.Random@7910769b
      			
      			boolean result1 = random1.nextBoolean();  //每次运行随机生成true或者false
      			System.out.println(result1);
      			
      			int result2= random1.nextInt();   //随机生成int区间内的数
      			System.out.println(result2);
      			
      			int result3 = random1.nextInt(10);  //随机生成一个0到10之间的数,包括0,但不包括10
      			System.out.println(result3);
      			
      			
      			Random random2 = new Random(1);
      			System.out.println(random2.nextInt());
      			System.out.println(random2.nextInt(100));
      			Random random3 = new Random(10L);
      			System.out.println(random3.nextInt());
    
    
    注意	
      	  当传入了一个种子数时,那么它调用方法的时候,答案就是固定的了,例如,当种子数为1时,它的nextInt()方法返回值永远是-1155869325,它的	nextInt(100)返回值永远是88
    

6.3 String类常用方法

  • 先来点开胃小菜
      System.out.println(10+20+"hello");
      System.out.println(10+"hello"+20);
      System.out.println("hello"+10+20);  //hello先和10进行字符串拼接(从左往右运算)
      System.out.println("hello"+(10+20));
      
    答案
      	 30hello
      	 10hello20
      	 hello1020
      	 hello30		
    ------------------------------------------------------	
    
     public int length()
     public int indexOf(int ch)
     public int lastIndexOf(String str)
     public String substring(int beginIndex)
     public String substring(int beginIndex, int endIndex)
     public String trim()
     public String[] split(String regex) 
     public char charAt(int index)
     public boolean endsWith(String suffix)
     public byte[] getBytes() 
     public String toLowerCase() 
     public String toUpperCase()
     public String concat(String str)
    
     例子1
       	public static void main(String[] args) {
      	
      		//public int indexOf(int ch) 传的是ASCII码值,搜索第一个出现的字符ch(或字符串value),如果没有找到,返回-1
      		//public int indexOf(String value) 搜索第一个出现的字符ch(或字符串value),如果没有找到,返回-1
      				
      		//常用ASCII码值 A:65   a:97    0:48
      		String str = "abcAbabkmn";
      		int num = str.indexOf(65);
      		System.out.println(num);					//3
      		System.out.println(str.indexOf("a"));	    //0
      				
      		
      		//public int lastiIndexOf(int ch) 传的是ASCII码值,搜索最后一个出现的字符ch(或字符串value),如果没有找到,返回-1
      		//public int lastIndexOf(String value) 搜索最后出现的字符ch(或字符串value),如果没有找到,返回-1
      		System.out.println(str.lastIndexOf("a"));	//5
      			
      			
      		//public String substring(int index)提取从位置索引开始的字符串部分
      		String newStr =str.substring(3);
      		System.out.println(str);					//abcAbabkmn
      		System.out.println(newStr);					//Ababkmn
      		
      		// public String substring(int beginindex, int
      		// endindex):提取beginindex和endindex之间的字符串部分,包括开始索引的字符,不包括结束索引的字符
      		String newStr2 = str.substring(2, 4);
      		System.out.println(str);			//abcAbabkmn
      		System.out.println(newStr2);		//cA
      
      		// public String trim():返回一个前后不含任何空格的调用字符串的副本
      		String str3 = "   abc    qwert    ";
      		String newStr3 = str3.trim();
      		System.out.println(str3); 			//   abc    qwert    
      		System.out.println(newStr3); 	//abc    qwert
      		System.out.println("-----------------");
      
      		// String[] split(String regex) :根据拆分规则对字符串进行拆分
      		String song = "长亭外,古道边,芳草碧连天,晚风拂,柳笛声残,夕阳山外山";
      		String[] strs = song.split(",");
      		for (String string : strs) {
      			System.out.println(string);
      		}
      
      		// 我爱你你不爱我但是我很爱你可我就是不爱你
      		String love = "我爱你你不爱我但是我很爱你可我就是不爱你";
      		String[] loves = love.split("爱");
      		for (String string : loves) {
      			System.out.println(string);
      		}
      		System.out.println("--------------");
      				
      		char ch = love.charAt(1);
      		System.out.println(ch);					//爱
      		boolean result = love.endsWith("我就是不爱你");   	//根据字符串的结尾语句,判断是否相同
      		System.out.println(result);				//true
      				
      		System.out.println("--------------");
      				
      				
      		String love1 = "ABCDEFGHI"; //考虑到编码问题,所以不使用汉字
      		byte[] bytes = love1.getBytes();  //把字符串变成byte型数组
      		for (int i = 0; i < bytes.length; i++) {
      			System.out.print(bytes[i]+"--"+(char)bytes[i]+"\t");  //65--A	66--B	67--C	68--D	69--E	70--F	71--G	72--H	73--I	
      		}
      				
      		//toLowerCase()方法:将大写英文字母转换为小写
      		//toUpperCase()方法:将小写英文字母转换为大写
      		String str3 = "AbcdE";
      		System.out.println(str3.toLowerCase());   //abcde
      		System.out.println(str3.toUpperCase());   //ABCDE
    
      		//字符串的连接: +  concat()
      		String str5 = "大湖名称";
      		String str6 = "创新高地";
      		System.out.println(str5+str6);					//大湖名称创新高地
      		String result = str5.concat(str6);			
      		System.out.println(result);						//大湖名称创新高地
      }
    
    
    例子2
    
      //输入一行字符,分别统计出其中英文字母、空格、数字和其它字
      public class Demo01 {
      	public static void main(String[] args) {
      				Scanner sc = new Scanner(System.in);
      				String str = sc.nextLine();
      				int lat=0,spa=0,num=0,oth=0;
      				for(int i=0;i127){             //汉字都是大于127的
      						System.out.println("*");
      					}
      					
      					else if(str.charAt(i)==' ') {		 
      						spa++;
      					}
      					else if((str.charAt(i)>=65&&str.charAt(i)<=90)||(str.charAt(i)>=97&&str.charAt(i)<=122)) {  //65--90    97--122
      						lat++;
      					}
      					else if(str.charAt(i)>=48&&str.charAt(i)<=57) {		// 数0 到10的ASCII表   48--57
      						num++;
      					}
      				}
      				oth = str.length()-num-spa-lat;
      				System.out.println("字母个数:"+lat+"\n数字个数:"+num+"\n空格个数:"+spa+"\n其他字符个数:"+oth);
      	}	
      
      }
    

6.4 StringBuffer类常用方法

  •  我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。而StringBuffer就可以解决这个问题。
    
      StringBuffer与String都是final,不可被继承。
      StrinBuffer的操作都是在原有的基础上进行操作,不复制另一份
    
      public StringBuffer append(String str)  //添加字符串str,返回字符缓冲区
      public StringBuffer insert(int offset, String str)  //向任意位置,添加字符串str,返回字符缓冲区
      public synchronized String toString()
      public synchronized StringBuffer replace(int start, int end, String str)
    
    例子
        public static void main(String[] args) {
      		//将一个数字字符串转换成逗号分隔的数字串,即从右边开始每三个数字由逗号分隔
      		
      		
      		//第一步:获取键盘输入的数字
      		Scanner sc = new Scanner(System.in);
      		System.out.println("请输入一个串数字");
      		String num = sc.next();
      		
      		System.out.println("---------------");
      		//第二部:一会要使用StringBuffer里的insert()方法,所以先要转换成StringBuffer
      		StringBuffer sb = new StringBuffer(num);
      		System.out.println(sb);  //12345678
      		//向字符串中插入,从后面开始插入,也就是说要反着来插入
      		for(int i=sb.length()-3;i>0;i-=3){
      			sb.insert(i,","); 
      		}
      		
      		System.out.println(sb);  //12,345,678
      	
      			
      		StringBuffer sb1 = new StringBuffer("我喜欢你");
      		StringBuffer sb2 = sb1.append("问世间情为何物,直教人生死相许");
      		System.out.println(sb1);	//我喜欢你问世间情为何物,直教人生死相许
      		System.out.println(sb2);	//我喜欢你问世间情为何物,直教人生死相许
    
      		StringBuffer sb3 = new StringBuffer("我喜欢你,b,是吧bb3");
      		StringBuffer sb4 = sb3.replace(5,8,"爱"); //会把[5,8)去掉,换成爱  (从0开始数)
      		System.out.println(sb4);		//我喜欢你,爱吧bb3
      	}
    

7.日期类

7.1 Date类

  • 常用方法
      		public int getYear()   //需要加上1900
      		public int getDay()	   //星期日是0,星期六是6
    
    
    例子
      		public static void main(String[] args) {
      				Date  date =new Date();
    //一般来说只有重写toString()方法,输出类的引用才不会输出地址
      				System.out.println(date);  //Sat Jul 02 10:03:49 CST 2022
      				
      				
      				Demo01 d =new Demo01();
    // 对于引用类型在println输出,这个引用类型都会调用到toString()方法,Object中的toString()方法返回的值    getClass().getName() + "@" + Integer.toHexString(hashCode());
      				System.out.println(d);//cn.bdqn.demo02.Demo01@5ba51364
      				System.out.println(d.getClass().getName());   //	cn.bdqn.demo02.Demo01
      		
      		
      				int year = date.getYear()+1900;
      				System.out.println(year);
      				
      				int day = date.getDay();
      				System.out.println(day);
      				switch (day) {
      				case 0:
      					System.out.println("星期日");
      					break;
      				case 6:
      					System.out.println("星期六");
      					break;
      			}
      		}
    

7.2 SimpleDateFormat类

  • public final String format(Date date)
    
    例子
      	    Date date =new Date();
      		System.out.println(date);
      		
      		SimpleDateFormat sdf = new SimpleDateFormat();
      		System.out.println(sdf);  //java.text.SimpleDateFormat@b5341f2a
      		
      		String str =sdf.format(date);
      		System.out.println(str);   //22-7-2 上午11:00
      		
      		
      		SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      		String str1 =sdf1.format(date);
      		System.out.println(str1); 		//2022-07-02 11:02:59
    

7.3 Calendar类

  • public int get(int field)
    
    
    例子
    public static void main(String[] args) {
      			// 通过查询API知道Calendar类是一个抽象类,不能直接实例化,
      			// 可以调用Calendar类中的getInstance() 方法获得getInstance() 方法获得Calendar类的引用
    
      			Calendar cal = Calendar.getInstance();
      			System.out.println(cal);
      			// 输出上面的cal的可以得到很多的数据,比如年月日时分秒星期数等,但是形式不是我们想要的,所以我们要进行转换
      	
      			// 获取年
      			int year = cal.get(Calendar.YEAR);
      			System.out.println(year);		//2022
      	
      			// 获取月份
      			int month = cal.get(Calendar.MONTH);// 在日历cal中第一个月用0表示,第二个月用1表示,以此类推
      			System.out.println(month + 1);	//7
      	
      			// 获取日
      			int day = cal.get(Calendar.DAY_OF_MONTH);
      			System.out.println(day);		//2
      	
      			// 获取时分秒
      			int hour = cal.get(Calendar.HOUR);
      			int minute = cal.get(Calendar.MINUTE);
      			int second = cal.get(Calendar.SECOND);
      			System.out.println(hour+":"+minute+":"+second);	  //11:56:6
      			
      			//获取今天是这一年的第多少天
      			int dayYear=cal.get(Calendar.DAY_OF_YEAR);
      			System.out.println("今天是这一年的第"+dayYear+"天");     //今天是这一年的第183天
      			
      			//获取星期
      			int dayWeek =cal.get(Calendar.DAY_OF_WEEK);
      			System.out.println(dayWeek-1); 		//6
      	
      }
    

输入和输出流

8.1 File类

  • File类常用方法
    
    public boolean exists()    判断文件或目录是否存在
    public boolean isFile() 	 判断是否是文件
    public boolean isDirectory()	判断是否是目录
    public String getPath()		返回此对象表示的文件的相对路径名
    public String getAbsolutePath()  返回此对象表示的文件的绝对路径名
    public boolean createNewFile() throws IOException  创建名称的空文件,不创建文件夹
    public boolean mkdirs()		可以创建多个文件夹
    public boolean mkdir()  		只能创建一个文件夹
    public String getName()	 获取文件夹的名称或者文件的名称(带后缀)
    
    public boolean delete()   删除此对象指定的文件或目录
    public long length()	返回文件的长度,如果文件不存在,则返回0L
    
    
    例子
    public class FileDemo01 {
      	public static void main(String[] args) {
      
      		//创建File类对象
      		File file = new File("D:\\demo.txt");   //第一个\是转义字符,第二个\则是斜杠
      		File file1 =new File("D:\\demo");
      		
      		
      		//通过file调用方法实现对文件属性的操作
      		
      		//exists():判断文件或目录是否存在
      		boolean result1 = file.exists();  //存在则返回true,不存在则返回false
      		System.out.println("file对象指向的文件存在:"+result1);
      		
      		//boolean isFile()
      		boolean result2= file.isFile();
      		System.out.println("fiel对象指向的是一个文件:"+result2);
      		
      		//boolean isDirectory()
      		boolean result3 = file1.isDirectory();
      		System.out.println("file1对象指向的是一个目录:"+result3);
      		
      		//String getPath()
      		String path =file.getPath();  
      		System.out.println("file对象指向的文件路径:"+path);
      
      		//String getAbsolutePath()
      		String absolutePath = file.getAbsolutePath();
      		System.out.println("file对象指向的文件路径:"+absolutePath);
      	
      		//boolean createNewFile(); 
      		File file2 =new File("test.txt");
      		boolean result4;
      		try {
      			result4 = file2.createNewFile();	 //只能创建文件,不能创建文件夹
      			System.out.println("file2对象指向的文件创建成功:"+result4);
      		} catch (IOException e) {
      			e.printStackTrace();
      		}
      		String path1 =file2.getPath();  					//相对路径指的是相对于谁的路径(这里相对的是src路径)
      		System.out.println("file对象指向的文件路径:"+path1);
      		String absolutePath1 = file2.getAbsolutePath();
      		System.out.println("file对象指向的文件路径:"+absolutePath1);	//绝对路径是输出磁盘整个目录
      		
      		
      		//boolean mkdir()   //只能创建一个文件夹
      		//boolean mkdirs()  //可以创建多个文件夹 
      		File file3 =  new File("D:\\mm\\aa\\bb");
      		boolean result5 = file3.mkdirs();
      		System.out.println("多级文件夹创建成功:"+result5);		//只要保证bb文件夹没有就好,不需要担心是否有mm\\aa文件夹
      		
      		
      		//String getName()  获取文件夹的名称或者文件的名称(带后缀)
      		String result6 = file.getName();
      		System.out.println(result6);
      		
      
      		// boolean delete()   删除文件或者文件夹
      		System.out.println("file1对象指向的文件删除成功:" + file1.delete());
      		System.out.println("file2对象指向的目录删除成功:" + file2.delete());
    
      		//long length():获取文件内容的长度
      		File file4 = new File("D:/demo.txt");
      		System.out.println(file4.length());
      	}
      
      }
    

8.2 FileInputStream(输入流,从磁盘中读到内存 )类

  • FileInputStream是InputStream的子类,InputStream是抽象类,不能实例化
    
    
    例子
      		  
      	public class FileInputStreamDemo {
      	//以程序位中心。从磁盘上到程序中叫   读取,输入流
      		public static void main(String[] args) {
      	
      			//创建File类对象
      			File file =new File("d:\\demo.txt");
      			FileInputStream fis = null;				//局部变量需要赋初始值
      			//创建FileInputStream对象
      			try {
      				 fis = new FileInputStream(file);
      				 
      				 
      				//通过fis对象调用方法将文件里的内容读取进来
      	/*
      	 * 方式一
      				while(true){
      					int num = fis.read();  			//当读完之后没有字符的话会返回-1
      					if(num!=-1)
      						System.out.println((char)num);
      					else
      						break;
      				}
      	*/
      				 
      	//方式二		
      				 byte[] bytes = new byte[1024]; //定义一个大小位1024的byte型数组
      				// read()方法需要一个byte类型的参数,准备一个byte类型的参数
      				 int num = fis.read(bytes);			//返回值则是从文件中读取的内容长度
      				 for(int i=0;i

8.3 FileOutputStream

  • 构造方法
      public FileOutputStream(String name) throws FileNotFoundException
      		通过此构造方法创建的对象,使用write()方法写入数据的时候,会将文件中的数据全部进行覆盖	
      public FileOutputStream(String name, boolean append)throws FileNotFoundException		
       		通过此构造方法创建的对象,将第二个参数设置为true使用write()方法写入数据的时候,会在文件末尾继续写入,不会将文件中的数据全部进行覆盖,
       		若是false则会覆盖,和Demo01一样,因为boolean值默认是false
    
  • 例子1(写入1个字节)
      
      public class FileOutputStreamDemo01 {
      
      	public static void main(String[] args) {
      		
      		//创建一个OutputStream类对象指向FileOutputStream类对象
      		OutputStream os = null;
      		try {
      		//FileOutputStream(String path) 通过此构造方法创建的对象,使用write()方法写入数据的时候,会将文件中的数据全部进行覆盖	
      		    os = new FileOutputStream("d:\\demo.txt");
      			//将数据写入到自定义的文件中
      			os.write(65);
      			System.out.println("数据写入完毕");
      		} catch (FileNotFoundException e) {
      			// TODO Auto-generated catch block
      			e.printStackTrace();
      		} catch (IOException e) {
      			// TODO Auto-generated catch block
      			e.printStackTrace();
      		}finally{
      			if(os!=null)
      				try {
      					os.close();
      				} catch (IOException e) {
      					// TODO Auto-generated catch block
      					e.printStackTrace();
      				}
      		}
      	}
      }
    
    
    例子2(解决例子1的缺陷,写入一个字符串)
      	  public class FileOutputStreamDemo03 {
      			public static void main(String[] args) {
      				FileOutputStream fos =null;
      				//创建File类对象
      				File file = new File("d:\\demo.txt");
      				try {
      				    fos = new FileOutputStream(file,true);
      					//将一串字符串写入到文件中去
      					String str = "hello world";
      					
      					//getBytes()将一个字符串转化为一个字节数组byte[]的方法
      					byte[] bytes = str.getBytes();
      		
      					fos.write(bytes);
      					
      				} catch (FileNotFoundException e) {
      					// TODO Auto-generated catch block
      					e.printStackTrace();
      				} catch (IOException e) {
      					// TODO Auto-generated catch block
      					e.printStackTrace();
      				}finally{
      					if(fos!=null)
      						try {
      							fos.close();
      						} catch (IOException e) {
      							// TODO Auto-generated catch block
      							e.printStackTrace();
      						}
      				}					
      		  }
      	}
      	
    注意
    	String类中比较重要的一个方法getBytes(),将一个字符串转化为一个字节数组byte[]的方法,然后再写入磁盘中
    

8.4 流类的总结

  • Read是从磁盘中读		
    Write是把内容写道磁盘中
    抽象类的第一原则是不能创建对象,但非抽象类的子类可以向上转型
      	 1 Reader类(抽象类)的子类
      		 	1.1 BufferedReader
      		 	 	BufferedReader构造方法参数需要用到Reader类(InputStreamReader),而InputStreamReader类的构造方法需要InputStream类(FileInputStream)
      		 	 		拥有的方法
      		 	 			String readLine()  
      		 	 			按行读取,每调用一次切换到下一行,直到下一行没数据,则返回-1
      		 	 		
      		 	1.2 InputStreamReader
      		 	 	InputStreamReader类的构造方法需要InputStream类(FileInputStream)并且可以加另外一个String类型的参数charset,也可以不加
      		 	 		拥有的方法
      		 	 			int read()         
      		 	 			读一个字符,每调用一次切换到下一个字符,直到没数据,则返回-1。它返回的是这个字符对应的ASCII码对应的数 例如 a对应97 
      		 	 	1.3 FileReader类是InputStreamReader类的子类
      		 	 			FileReader构造方法需要用到File类或者直接给一个String类型的磁盘地址
       	 					拥有的方法
      		 	 			int read()         
      		 	 			读一个字符,每调用一次切换到下一个字符,直到没数据,则返回-1。它返回的是这个字符对应的ASCII码对应的数 例如 a对应97 
      		 	 			
      		 	 			
       	  2 InputStream类(抽象类)的子类
       	 		2.1 FileInputStream
       	 		    FileInputStream构造方法参数有两种,一种是放File类的对象,另一种是直接放String类型的地址
       	 		 		拥有的方法
       	 		 			int read(byte b[])  
       	 		 			返回值则是从文件中读取的内容长度。只需要定义一个byte型数组,规定大小,直接把这个byte型数组对象拿给read中就行,
       	 		 			然后执行完read方法之后,byte型数组就把那些ASCII码数字存储到数组里面了
       	 		 								
       	 		 			
       	 		 写入对象的类(InputStream类的子类),这个对象类要实现Serializable
       	 		2.2 ObjectInputStream
       	 		 	ObjectInputStream类的构造方法需要InputStream类(FileInputStream)
       	 		 		拥有方法
       	 		 			Object readObject()			
       	 		 			把用ObjectOutputStream类存放的数据,用ObjectInputStream读出来
       	 		2.3 ObjectOutputStream
       	 			ObjectOutputStream类的构造方法需要OutputStrem类(FileOutputStream)
       	 				拥有方法
       	 					void writeObject(Object obj)	
       	 					把创建好的对象传给这个参数obj(也可以用集合把对象存储起来,然后把集合对象传给obj),然后就可以写入到磁盘中,然后就可以使用ObjectInputStream读出来
       	 					
       	 	序列化和反序列化
       	 			1、序列化和反序列化的定义:
      					   Java序列化就是指把Java对象转换为字节序列的过程。(将对象存储到文件中)
      					   Java反序列化就是指把字节序列恢复为Java对象的过程。(从文件中读取对象信息)
    
      				2、序列化最重要的作用:
      					   在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
    
     反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
    
      			   总结:核心作用就是对象状态的保存和重建。
       	 					
       	 					
       	  3 二进制输入输出图片、音频等
       	 	   3.1 DataInputStream类的构造方法需要InputStream类(FileInputStream)
       	 			    拥有方法
       	 				int read()         
       	 				读一个字符,每调用一次切换到下一个字符,直到没数据,则返回-1。它返回的是这个字符对应的ASCII码对应的数 例如 a对应97 
       	 					
       	 	   3.2 DataOutputStream类的构造方法需要OutputStream类(FileOutputStream类)
       	 				拥有方法
       	 				public synchronized void write(int b)    
       	 				写一个数字,该数字是对应ASCII码表上的
       	 			
       	   4 同理上方			 	 		 
       	 	   4.1 BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:\\demo.txt",true)));
       	 	 		拥有方法
       	 	 			void newLine()  		   写入换行
       	 	 			void write(String str)    String接收的是写入磁盘中的内容
       	 	 			void flush()			    写完之后需要刷新一下缓冲区才可以
       	 	 			
       	 	   4.2 OutputStreamWriter类的两个构造方法,可以加编码格式
       	 	   		OutputStreamWriter(OutputStream os)
       	 	   		OutputStreamWriter(OutputStream os,String charset)
       	 	 			拥有方法
       	 	 			void write(String str)    String接收的是写入磁盘中的内容
       	 	 		4.3 FileWriter类是OutputStreamWriter类的子类
       	 	 			FileWriter(File file)
       	 	 			FileWriter(String path)
       	 	 			FileWriter(File file,boolean bool)
       	 	 			FileWriter(String path,boolean bool)
       	 	 				拥有方法
       	 	 				void write(String str)    String接收的是写入磁盘中的内容
       	 	 			
       	 	   4.4 FileOutputStream("d:\\demo.txt",true)
       	 	   
       	 	   		 构造方法
      				 FileOutputStream(File file)
      				 FileOutputStream(String path)
      				 FileOutputStream(File file , boolean bool)
      				 FileOutputStream(String path, boolean bool)
    

8.5 BufferedReader类

public class BufferedReaderDemo01 {
	public static void main(String[] args) {
		//创建BufferedReader类对象
		BufferedReader br = null;
		
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream("d:\\demo.txt"),"utf-8"));
			while(true){
				String str1 = br.readLine();
				if(str1!=null)
					System.out.println(str1);
				else 
					break;
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

8.6 BufferedWriter类

	public class BufferedWriterDemo01 {
		public static void main(String[] args) {
			BufferedWriter bw =null;
			//创建BufferedWriter类对象
			try {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:\\demo.txt",true)));
				bw.newLine();
				bw.write("随意");
				bw.newLine();
				bw.write("吃饭 喝酒");
				bw.flush();    //需要这个把缓冲区冲进磁盘中
				System.out.println("数据写入成功");
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				try {
					bw.close();   
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

8.7 DataInputStreamAndDataOutputStream类

public class DataInputStreamAndDataOutputStreamDemo01 {
		public static void main(String[] args) {
			//创建FileInputStream类对象
			FileInputStream fis = null;
			//创建DataInputStream类对象
			DataInputStream dis = null;
			//创建FileOutputStream类对象
			FileOutputStream fos = null;
			//创建DataOutputStream类对象
			DataOutputStream dos =null;
			try {
				 fis = new FileInputStream("d:\\beautiful.jpg");//这个是原有的	
				 dis = new DataInputStream(fis);
				 fos = new FileOutputStream("d:\\girl.jpg"); //这个是生成的
				 dos = new DataOutputStream(fos);
				 byte[] bytes = new byte[2000000];
				 System.out.println();
				while(true){
					int num = dis.read();
					if(num!=-1)
						dos.write(num);
					else
						break;
				}
				System.out.println("程序执行完毕");
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				try {
					dos.close();
					fos.close();
					dis.close();
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
}

8.8 ObjectOutputStreamAndObjectInputStream类

	public class ObjectOutputStreamDemo02 {
		public static void main(String[] args) {
			try {
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\student.txt"));
			
				Student stu1 = new Student("张三","20");
				Student stu2 = new Student("李四","21");
				Student stu3 = new Student("王五","22");
				Student stu4 = new Student("赵六","23");
				
				List<Student> list = new ArrayList<Student>();
				list.add(stu1);
				list.add(stu2);
				list.add(stu3);
				list.add(stu4);
				
				oos.writeObject(list);
				System.out.println("多个对象写入完毕");	
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
}



	public class ObjectInputStreamDemo02 {
	
		public static void main(String[] args) {
				ObjectInputStream ois;
				try {
					ois = new ObjectInputStream(new FileInputStream("D:\\student.txt"));
					Object object = ois.readObject();
					ArrayList al = (ArrayList)object;
					for (Object object2 : al) {
						System.out.println(object2);
					}
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
		}
	}



	public class Student implements Serializable{
			private String name;
			private String age;
			
			public Student(String name, String age) {
				super();
				this.name = name;
				this.age = age;
			}
			public String getName() {
				return name;
			}
			public void setName(String name) {
				this.name = name;
			}
			public String getAge() {
				return age;
			}
			public void setAge(String age) {
				this.age = age;
			}	
			@Override
			public String toString() {
				return "Student [name=" + name + ", age=" + age + "]";
			}	
		}

8.9 FileReader类

public class FileReaderDemo01 {
	public static void main(String[] args) throws IOException {
//创建FileReader类对象
		FileReader fr  = null;
		fr = new FileReader("D:\\demo.txt");
		while(true){
			int num =fr.read();
			if(num!=-1)
				System.out.print((char)num);
			else
				break;
		}
		fr.close();
	}
}

8.10 FileWriter类

public class FileWriterDemo01
	public static void main(String[] args) {
		//创建FileWriter类对象
		FileWriter fw = null;
		try {
			fw = new FileWriter("D:\\demo.txt");
			fw.write("你好,我是FileWriter");
			System.out.println("数据写入完毕");
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

8.11 InputStreamReader类

public abstract class InputStreamReaderDemo02 {
	public static void main(String[] args) {
		InputStreamReader ir =null;
		try {
			ir = new InputStreamReader(new FileInputStream("D:\\demo.txt"),"UTF-8");
			
			char[] chars = new char[1024];
			//read(char[] ch从流中读取数据,并将数据存储再ch这个数组中,返回值表示从流中读取的数据个数
			int num =ir.read(chars);
			
			//遍历数组chars,获取读取的数据
			for(int i=0;i<num;i++){
				System.out.print(chars[i]);
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(ir!=null)
				try {
					ir.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

8.12 OutputStreamWriter类

public class OutputStreamWriterDemo01 {
	public static void main(String[] args) {
		OutputStreamWriter osw =null;
		//创建OutputStreamWriter类对象
		try {
			osw = new OutputStreamWriter(new FileOutputStream("d:\\demo.txt",true));
			
			osw.write("hello java");
			System.out.println("数据写入完毕");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				osw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

8.13 图片保存到文本中并且可以复原

	public class txtPngDemo{
		public static void main(String[] args) throws Exception {
			jpgTxt();
			txtPng();
		}
		
 //将图片转为文本文件
		public static void jpgTxt()throws Exception{
			//创建写入流对象
			FileOutputStream outputStream =  new FileOutputStream("d:/1.txt");
			//输入流对象
			FileInputStream inputStream = new FileInputStream("D:/1.png");
			int b = -1;
			while((b = inputStream.read()) !=-1){
				byte[] bytes =( b+"").getBytes();		//把整形转换成字符串  String str = 1+"";  输出str就是字符串1
				outputStream.write(bytes);				//使用对象名,把存储在byte数组中的数字写道文件中
				outputStream.write(new byte[]{'\r'});  
	/*使用对象名,写入换行r或者n   因为write只支持int或者byte数组类型的参数   等价于 byte[] bytes1 = new byte[]{'\r'} 然后把bytes1传入.
	  这里的斜杠告诉程序我是个转义字符,接下来要做就是换行。  很像警察 先亮明身份,然后再行使权力				
	*/	
			}
			System.out.println("图片写到文本成功");
			outputStream.close();
			inputStream.close();
		}
		
//将文本文件转为图片格式文件
		public static void txtPng()throws Exception{
			//创建写入流对象
			BufferedOutputStream outputStream =  new BufferedOutputStream(new FileOutputStream("d:/4.png"));
			//输入流对象
			BufferedReader inputStream = new BufferedReader(new FileReader("d:/1.txt")) ;
			String str = null;
			while((str=inputStream.readLine()) !=null){
				byte a = (byte)Integer.parseInt(str);
				outputStream.write(a);
			}
			System.out.println("文本转换成图片成功");
			outputStream.close();
			inputStream.close();
		}
	}

多线程

  • 如果再一个进程中同时运行多个线程,用来完成不同的工作,则称之为多线程
    多个线程交替占用CPU资源,而非真正的并行执行	 
    
  • 进程和线程的关系       
      	 一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。
      	 
      	 与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,
      	 所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
    

9.1 Thread类

  • Java中创建多线程的两种方式 
    		java.lang包下的Thread类,Thread类支持多线程编程
    		java.lang包下的Runnable接口
    		
    主线程只有一个main()方法,它必须最后完成执行,因为他执行各种关闭动作
    
    Thread类方法
            currentThread()     //获取当前线程对象
            getName()			//获取当前线程的名称
            getPriority()		//获取当前线程的优先级
            setName()			//设置线程的名称
            setPriority()		//设置线程优先级
    
    Thread类的静态字段
            MAX_PRIORITY   10
            MIN_PRIORITY    1
            NORM_PRIORITY   5
    
    例子
      	 public class ThreadDemo01 {
      		public static void main(String[] args) {
      			//main方法是程序的主入口,是一个线程
      			//currentThread() 获取当前线程对象
      			Thread thread = Thread.currentThread();
      			
      			//getName()  获取当前线程的名称
      			String name = Thread.currentThread().getName();
      			System.out.println(name);					//main
      			
      			//getPriority() 获取当前线程的优先级
      			int priority = thread.getPriority();
      			System.out.println(priority);				//5
      			
      			//setName() 设置线程的名称
      			thread.setName("随意");						//随意
      			System.out.println(thread.getName());
      			
      			//setPriority()  设置线程优先级
      			thread.setPriority(1);				
      			System.out.println(thread.getPriority());	//1
      			
      			System.out.println("线程优先级最高值:"+Thread.MAX_PRIORITY);	//10
      			System.out.println("线程优先级最低值:"+Thread.MIN_PRIORITY);	//1
      			System.out.println("线程优先级默认值:"+Thread.NORM_PRIORITY);	//5
      		}
      	}
    
  • 继承Thread类实例
    
      	public class Test {
      	   public static void main(String[] args) {
      			//创建线程类对象
      			MyThread mt1 = new MyThread("天山童姥");
      			MyThread mt2 = new MyThread("逍遥子");
      	
      			// start()方法是启动线程的方法
      			mt1.start();
      			mt2.start();
      			//当同时启动两个线程以后,会出现两个线程交替占用CPU执行代码的结果
      		}
      	}
    
      	//一个类要定义成线程类,可以通过继承Thread类来实现,然后重写Thread类的run()方法
      	public class MyThread extends Thread{
      	
      		public MyThread(){
      		}
      		
      		public MyThread(String name){
      			super(name);
      		}
      		@Override
      		public void run(){
      			//在重写的run()方法中编写你要执行的代码,使用循环输出1-20
      			for(int i=1;i<=20;i++){
      				System.out.println(Thread.currentThread().getName()+"-"+i);
      			}
      		}
      	}
    
    
    
    实现Runnable接口实例
    
      	public class Test {	
      	   public static void main(String[] args) {
      			//创建线程类对象
      			MyRunnable mt1 = new MyRunnable();
      			Thread thread1 = new Thread(mt1,"千里眼");
      			Thread thread2 = new Thread(mt1);
      			thread1.start();
      			thread2.start();
      			//start()方法是Thread类中的方法,而我们需要通过start()放啊来调用run()方法,不能直接调用run()方法
      			//但是Runnable接口中只有一个抽象方法run()方法,那么实现Runnable接口的子类不能调用start()方法
      			//解决办法
      			//将实现Runnable接口的类对象作为参数传递给Thread构造方法,然后通过Thread类对象调用start()方法
      		}
      	}
    

9.2 锁机制

		/**
		 * 使用同步代码块的方式解决取款问题
		 * Account类:银行账户类
		 */
		public class Account {
		
			private int balance = 500; //余额
			public int getBalance(){
				return balance;
			}
			
			//取款
			public void withdraw(int amount){
				balance = balance-amount;
			}
		}


		 
		 //TestAccount类:取款的线程类 
		public class TestAccount implements Runnable {
			// 所有用TestAccount对象创建的线程共享同一个账户对象
			private Account acct = new Account();
		
			public void run() {
				for (int i = 0; i < 5; i++) {
					makeWithDrawal(100); // 每次取款100元
					if (acct.getBalance() < 0) {
						System.out.println("账户透支了!");
					}
				}
			}
		
			// 取款
			private void makeWithDrawal(int amt) {
				synchronized (acct) { // 同步查询和取款的代码块
					if (acct.getBalance() >= amt) {    // 如果余额大于100,则足够,可以取款
						System.out.println(Thread.currentThread().getName() + "准备取款");
						try {
							Thread.sleep(500); // 0.5秒后实现取款
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						
						acct.withdraw(amt);
						System.out.println(Thread.currentThread().getName() + "完成取款");
					} else {
						// 余额不足给出提示
						System.out.println("余额不足支付" + Thread.currentThread().getName()
								+ "的取款,余额为" + acct.getBalance());
					}
				}
			}
		}

		//测试类
		public class Test {
		
			public static void main(String[] args) {
				// 创建两个线程
				TestAccount r = new TestAccount();
				Thread one = new Thread(r);
				Thread two = new Thread(r);
				one.setName("张三");
				two.setName("张三老婆");
				// 启动线程
				one.start();
				two.start();
			}	
		}
	//使用锁,永远不会出行透支情况		

9.3 join方法和yield方法

  • join方法是强制当前线程全部执行完,其它线程等待
    
		public class MyThread implements Runnable {
			@Override
			public void run() {
				for(int i =0;i<20;i++){
					System.out.println(Thread.currentThread().getName()+"运行第"+(i+1)+"次");
				}
			}
		}

		public class Test {
			public static void main(String[] args) {
				MyThread mt = new MyThread();
				Thread t = new Thread(mt,"尼古拉斯");
				t.start();
				
				for(int i=0;i<10;i++){
					if(i==5){
						try{
							t.join();   //强制MyThread线程执行,其它线程等待,直到这个线程死亡
						}
						catch(InterruptedException e){
							e.printStackTrace();
						}
					}
					System.out.println(Thread.currentThread().getName()+"运行第"+(i+1)+"次");
				}
			}
		}
/*
	执行结果
			main运行第1次
			尼古拉斯运行第1次
			main运行第2次
			尼古拉斯运行第2次
			main运行第3次
			尼古拉斯运行第3次
			main运行第4次
			尼古拉斯运行第4次
			main运行第5次
			尼古拉斯运行第5次
			尼古拉斯运行第6次
			尼古拉斯运行第7次
			尼古拉斯运行第8次
			尼古拉斯运行第9次
			尼古拉斯运行第10次
			尼古拉斯运行第11次
			尼古拉斯运行第12次
			尼古拉斯运行第13次
			尼古拉斯运行第14次
			尼古拉斯运行第15次
			尼古拉斯运行第16次
			尼古拉斯运行第17次
			尼古拉斯运行第18次
			尼古拉斯运行第19次
			尼古拉斯运行第20次
			main运行第6次
			main运行第7次
			main运行第8次
			main运行第9次
			main运行第10次

*/
  • yield方法是暂停当前线程,允许其他具有相同优先级的线程获得运行机会,该线程处于就绪状态,不转为阻塞状态。
    只是提供一种可能,但是不能保证一定会实现礼让
    
	public class MyThread implements Runnable {
		@Override
		public void run() {
			for(int i =0;i<=5;i++){
				System.out.println(Thread.currentThread().getName()+"正在运行:"+i);
				if(i==3){
					System.out.println(Thread.currentThread().getName()+"线程礼让:");	
					Thread.yield();//线程礼让,只是提供一种让其它线程获得CPU资源的机会,自己也会再次去抢占CPU资源
				}
			}
		}

		public class Test {
			public static void main(String[] args) {
				//创建两个线程对象
				MyThread mt =new MyThread();
				Thread  t1 = new Thread(mt,"A");
				Thread  t2 = new Thread(mt,"B");
		
				t1.start();
				t2.start();
			}
		}
/*
		B正在运行:0
		B正在运行:1
		B正在运行:2
		B正在运行:3
		B线程礼让:
		A正在运行:0
		A正在运行:1
		B正在运行:4
		A正在运行:2
		B正在运行:5
		A正在运行:3
		A线程礼让:
		A正在运行:4
		A正在运行:5
*/

注意:
	从这里我们可以推断出,输出语句是加锁的,否则,我打印一部分,下一部分还没来的及打印

9.4 return break continue

  • 结束方法的关键字是return   
    结束循环语句的关键字是break(可以指定跳出哪一个循环  a:while(true){while(){break a;}})    
    跳过这一次循环是continue
    

9.5 线程同步的方式

  • 同步方法
           使用synchronized修饰的方法,就叫做同步方法,保证一个线程执行该方法的时候,其他线程只能在方法外等着。
    
    例子
      	public class Mythread1 implements Runnable {
      	    private int ticket = 10;
      	    @Override
      	    public void run() {
      	        while (true) {
      	            if (sellTicket() == false) {
      	                break;
      	            }
      	        }
      	    }
      	
      	    public synchronized boolean sellTicket() {
      	        if (ticket <= 0) {
      	            System.out.println(Thread.currentThread().getName() + "票已售罄");
      	            return false;
      	        } else {
      	            ticket--;
      	            System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩" + ticket + "张票");
      	            try {
      	                Thread.currentThread().sleep(500);
      	            } catch (InterruptedException e) {
      	                e.printStackTrace();
      	            }
      	            return true;
      	        }
      	    }
      	}
    
  • 同步代码块
    
    代码格式
    		synchronized(同步锁){   //注意:同步锁可以是任意对象
      		    需要同步操作的代码
      		}
      
      	
    例子
      		public class Mythread1 implements Runnable {
      		    private int ticket = 10;
      		    Object object = new Object();
      		    @Override
      		    public void run() {
      		        while (true) {
      		            synchronized (object) {//锁对象可以是任意对象
      		                if (ticket <= 0) {
      		                    System.out.println(Thread.currentThread().getName() + "票已售罄");
      		                    break;
      		                } else {
      		                    ticket--;
      		                    System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩" + ticket + "张票");
      		                    try {
      		                        Thread.currentThread().sleep(500);
      		                    } catch (InterruptedException e) {
      		                        e.printStackTrace();
      		                    }
      		                }
      		            }
      		        }
      		    }
      		}
    
  •  Lock锁(ReentrantLock类)
      		同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
    
      方法:
      		public void lock() :加同步锁。
      		public void unlock() :释放同步锁。
      		
      例子
      		public class Mythread1 implements Runnable {
      		    private int ticket = 10;
      		    Lock lock = new ReentrantLock();
      		    @Override
      		    public void run() {
      		        while (true) {
      		            lock.lock();
      		            try {
      		             if (ticket <= 0) {
      		                System.out.println(Thread.currentThread().getName() + "票已售罄");
      		                break;
      		            }
      		                ticket--;
      		                System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩" + ticket + "张票");
      		                try {
      		                    Thread.currentThread().sleep(500);
      		                } catch (InterruptedException e) {
      		                    e.printStackTrace();
      		                }
      		            } finally {
      		                lock.unlock();
      		            }
      		        }
      		    }
      		}
    

并发编程

  • 原文链接  https://blog.csdn.net/weixin_41968788/article/details/118968747
    

10.1 并发编程三大特性

  • 可见性,有序性,原子性   
    
     
    volatile保证可见性与有序性,但不保证原子性
    
    
    例子
    		public class VolatileVisibilityTest extends Thread{
      		    private static boolean initFlag = false;
      		    public static void main(String[] args) throws InterruptedException {
      		    
      		        Thread t = new Thread(new Runnable() {
      		            @Override
      		            public void run() {
      		            	System.out.println("waiting data");
      		                while (!initFlag){}
      		                System.out.println("==========success"); 
      		            }
      		        });
      		        t.start();
      		        Thread.sleep(2000);//模拟有一堆代码要执行
      		        
      		        Thread t1 = new Thread(new Runnable() {
      		            @Override
      		            public void run() {
      			            System.out.println("prepare data........");
                 		    initFlag = true;
                  			System.out.println("prepare data end......");
      		            }
      		        });
      		        t1.start();
      		    }  
      		}
      
      执行结果如下
    

    在这里插入图片描述

      	   执行上面代码,控制打印内容如下,发现程序并没有停下来,说明第一个线程并不知道共享变量initFlag已经被改为true了,
      	   事实上第二个线程改是自己工作内存里面的变量副本,第一个线程工作内存里面的变量副本还是false。	  
    
    
    怎么解决这个问题呢?
    		如果想要第一个线程立刻知道共享变量已经修改了,只要给共享变量initFlag加上volatile关键字  
    		private volatile static boolean initFlag = false;
    

Java大全(二)_第3张图片

  • 线程1
      
      	从主内存中read共享变量initFlag到线程1的工作内存中;
      	接着从工作内存中use共享变量去处理,进入循环。
      	
    线程2
      	从主内存中read共享变量initFlag到线程2的工作内存中;
      	从工作内存中use共享变量去处理,变量值修改为true;
      	把修改后的共享变量initFlag重新assign到工作内存中;
      	把工作内存中修改后的共享变量initFlag再store到主内存中;
      	把store过去的共享变量initFlag再write给主内存中的变量。
      	那么为什么给共享变量initFlag加上volatile关键字之后,线程1就能感知到共享变量修改了呢?就不得不提缓存一致性协议了。
    

Java大全(二)_第4张图片

  • 总线使用缓存一致性协议MESI,开启总线嗅探机制。
    当线程2修改了共享变量initFLag的值后,立马(线程2不再往下继续执行)线程1使工作内存中的变量initFlag值失效,当线程1再使用时又会从主内存中重新读取。
    
  • 总结
      	多个cpu从主内存中读取同一个数据到各自高速缓存,当其中的某个cpu修改了缓存里的数据,该数据会马上同步回主内存,
      	其他cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效,再使用时重新从主内存中读取。
      	不同的处理器使用的缓存一致性协议可能不同。
    

10.2 JMM有序性

  • 执行下面一段代码,是否存在a=1,b=1这样情况呢?
    
		public class VolatileOrderTest {
		    static int a = 0, b = 0;
		    static int x = 0, y = 0;
		    public static void main(String[] args) throws InterruptedException {
		        for(int i = 0;;i++){
		            i++;
		            x = 0; y = 0;
		            a = 0; b = 0;
		            Thread one = new Thread(new Runnable() {
		            	@Override
		            	public void run(){
		            		 try {
		                         Thread.sleep(1);
		                     } catch (InterruptedException e) {
		                         e.printStackTrace();
		                     }
		                     a = y;
		                     x = 1;
		            	}
		            });
		            
		            Thread two = new Thread(new Runnable() {
		            	@Override
		            	public void run(){
		            		  try {
		                          Thread.sleep(1);
		                      } catch (InterruptedException e) {
		                          e.printStackTrace();
		                      }
		                      b = x;
		                      y = 1;
		            	}
		            });
		            one.start();
		            two.start();
		            one.join();
		            two.join();
		            System.out.println("第" + i + "次 a=" + a + " b=" + b);
		            if (a==1 && b==1) break;
		        }
		    }
		}

Java大全(二)_第5张图片

  • 可以发现循环到1万多次的时候,出现了结果为:a=1,b=1的情况,
    
    这说明:
      线程one中x=1;比a=y;先执行,线程two中y=1;比b=x;先执行,两个线程代码实际的执行顺序都发生了变化,这就是指令重排现象
    
  • 什么是指令重排
      	java语言规范规定JVM线程内部维持顺序话语义。
      	即,只要程序的最终结果与它顺序化执行结果相同,那么指令的执行顺序可以与代码顺序不一致,此过程叫做指令的重排。
      	
      	指令重排序,在不影响单线程程序执行结果的前提下,计算机为了最大限度的发挥机器性能,会对机器指令进行重排序优化。
    
  • 指令重排的前提
      是不是所有的代码都可能发生指令重排呢?当然不是的,只有满足一定的条件,符合一些规则才会发生。
      
      as-if-serial
      as-if-serial语义的意思是:不管怎么重排序,单线程程序的执行结果不能被改变。编译器、runtime和处理器都必须遵守as-if-serial语义。
      
      为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作就可能被编译器和处理器重排序。
    
    
      int i = 0;
      int j = i + 1; //下面这条语句就依赖上面的语句,不会发生指令重排
    

通信

三次握手四次挥手

  • TCP与UDP都工作在传输层,这两个目标都是在程序之间传输数据,数据可以是文本文件、视频、图片等。
    对于TCP协议与UDP协议来说,它们都是一堆二进制数。它们最大的区别是基于连接和基于非连接的
    例如(不考虑速度因素)
    		打电话 ----电话接通,互相通话,结束挂断						TCP
    		写信---对方是否收到,内容是否完整,多封信件顺序是否正确  		UDP
    
    		
    问题一:TCP是如何保证以上过程的呢?
    		分别为三次握手,传输确认,四次握手
    				
    		三次握手是建立连接的过程,当客户端向服务端发起连接时,会先发一包连接请求数据,过去询问一下,能否与你建立连接,这包数据我们称之为SYN包,
    		如果服务端同意连接,则回复一包SYN+ACK包,客户端收到之后回复ACK包。则到这客户端与服务端连接建立
    		因为这个过程中互相发送了三包数据,所以称之为三次握手
    		
    问题二:TCP三次握手第三次握手时ACK丢失怎么办?
    		 第三次的ACK在网络中丢失,那么Server 端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。
    		 如果重发指定次数之后,仍然未收到 client 的ACK应答,那么一段时间后,Server自动关闭这个连接,并从半连接队列(syns queue)移除
    		 
    问题三:为什么不是两次握手呢?
    			这是为了防止已经失效的请求报文突然有传到服务器引起错误
    			现假定一种异常情况,即A发出的SYN报文段并没有丢失,而是在某些网络节点长时间滞留了,以致延误到连接释放后的某个时间才到达B。
    			本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,却误以为是A又发出一次新的连接请求,于是就向A发出确认报文段,同意建立连接。
      			由于现在A并没有发出建立连接的请求,因此不会理睬B的确认,也不会向B发送数据,但B却以为新的运输连接已经建立了,并一直等待A发来的数据。B的许多资源就这样白白浪费了。
      			*******************************	
      			即:当A发送SYN+ACK给B,而客户端由于没有发送请求,不会接收服务端发送来的SYN+ACK请求,而此时服务端建立连接,客户端没有建立连接。(两次握手)
      			若是第三次,由于客户端没有发送ACK给服务端,所以问题二解答
      			*******************************	
      			
    问题四:一包数据可能被拆成多包发送,如何处理丢包问题?
    问题五:这些数据包到达的先后顺序不同,如何处理乱序问题
      		针对以上两个问题tcp协议为每个连接建立了一个发送缓冲区(存放的是需要发送的数据),从建立连接后的第一个字节的序列号为0,后面的每个字节的序列号就会增加1,
      		发送数据时,从发送缓冲区,取一部分数据组成发送报文,在其tcp协议头中会附带序列号和长度,接收端在收到数据后,需要回复确认报文,确认报文中的ACK等于接收序列号加长度,也就是下一包起始序列号。
      		这样一问一答的发送方式,能够使发送端确认发送的数据已经被对方收到。
      		发送端也可以一次发送连续的多包数据,接收端只需要回复一次ACK就可以了,这样发送端可以把待发送的数据分割成一系列的碎片,发送到对端,对端根据序列号和长度,在接收后重构出来完整的数据。
      		假设其中丢失了某些数据包,在接收端可以要求发送端重传,比如丢失了100-199这100个字节,接收端向发送端发送ACK=100的报文,发送端收到后重传这一包数据,接收端进行补齐。
      		以上过程不区分客户端和服务端,tcp连接是全双工的,对于两端来说均采用上述机制
    
    三次握手是为了解决网络信道不可靠的问题,在不可导的信道上建立可靠的链接
    
  • 四次挥手
      	  处于连接状态的客户端和服务端,都可以发起关闭连接请求,此时需要四次挥手来进行关闭连接
      	  假设客户端主动发起连接关闭请求,它需要向服务端发送一个FIN包,表示要关闭连接,自己进入终止等待1状态,这是第一次挥手
      	  服务端收到FIN包,发送一包ACK包,表示自己进入了关闭等待状态,客户端进入终止等待2状态,这是第二次挥手
      	  服务端此时还可以发送未发送的数据,而客户端还可以接受数据,待服务端发送完数据之后,发送一个FIN包,进入最后确认状态,这是第三次挥手
      	  客户端收到之后回复ACK包,进入超时等待状态,经过超时时间后关闭连接,而服务端收到ACK包后,立即关闭连接,这是第四次挥手
      	  
    问题一:为什么客户端需要等待超时时间?
    	  这是为了保证对方已收到ACK包。因为假设客户端发送完最后一包,ACK包后就释放了连接,一旦ACK包在网络中丢失,服务端将一直停留在最后确认状态
    	  如果客户端发送完最后一包ACK包后,等待一段时间,这时服务端因为没有收到ACK包将会重发FIN包,客户端会相应这个FIN包,客户端会重发ACK包并刷新超时时间。
    	  
    UDP
    	UDP协议是基于非连接的,发送数据就是简单的把数据包封装一下,然后从网卡发出去就可以了,数据包之间并没有状态上的联系。
    	所以UDP性能损耗非常小,对于CPU内存资源的占用也远小于TCP。
    	但是对于网络传输过程中产生的丢包UDP协议并不能保证,所以UDP在传输稳定性上要弱于tcp
    
  • 什么是线程通信
    		一个线程进行了规定操作后,就进入等待状态, 等待其他线程执行完他们的指定代码过后 再将其唤醒
    
  • TCP需要建立连接(使用流建立连接)
    UDP不需要建立连接
    127.0.0.1与localhost是一样的,代表的是当前自己计算机
    

普通通信TCP

  • Client
      	  创建客户端  new Socket("localhost",端口号)
      	  获取输出流	 new Socket("localhost",端口号).getOutputStream()
      	  输出信息 	 new Socket("localhost",端口号).getOutputStream().write(byte型数组对象)  //str.getBytes()
      	  关闭输出流	 new Socket("localhost",端口号).shoutdownOutput()
      	  
      	  获取输入流接收服务器端发送的相应信息
      	  			 new Socket("localhost",端口号).getInputStream()
      	  			 new BufferedReader(new InputStreamReader(new Socket("localhost",端口号).getInputStream()))
    
      例子	(getBytes()方法重要)
      		public class Client {
      			public static void main(String[] args) {
      				//创建Socket对象
      				Socket socket =null;
      				OutputStream os =null;
      				InputStream is =null;
      				BufferedReader br =null;
      				try {
      					//通信链路的客户端端点创建成功
      					socket = new Socket("localhost", 10088);
      					//获取输出流将登录信息发送给服务器端
      					os =socket.getOutputStream();
      					
      					String str = "用户名:tom,密码:123456";
      					byte[] bytes=str.getBytes();
      					//输出信息
      					os.write(bytes);
      					System.out.println("向服务器发送请求成功!");
      					//关闭输出流
      					socket.shutdownOutput();
      					
      					//获取输入流接收服务器端发送的响应信息
      					is = socket.getInputStream();
      					br = new BufferedReader(new InputStreamReader(is));
      					String str2;
      					while((str2=br.readLine())!=null){
      						System.out.println("这里是客户端,接收到的服务器发送来的响应信息为:"+str2);
      					}
      					
      				} catch (UnknownHostException e) {
      					e.printStackTrace();
      				} catch (IOException e) {
      					e.printStackTrace();
      				}finally{
      					try {
      						br.close();
      						is.close();
      						os.close();
      						socket.close();
      					} catch (IOException e) {
      						// TODO Auto-generated catch block
      						e.printStackTrace();
      					}
      				}
      			}
      		}
    
  • Server端		  
    	创建ServerSocket	new ServerSocket(端口号)
    	侦听客户端的请求		new ServerSocket(端口号).accept()
    	获取输入流接受客户端的请求信息
    						new ServerSocket(端口号).accept().getInputStream()
    						new BufferedReader(new InputStreamReader(new ServerSocket(端口号).accept().getInputStream())
    						
    	获取输出流向客户端发送响应消息
        					new ServerSocket(端口号).accept().getOutputStream()
        					new ServerSocket(端口号).accept().getOutputStream().write(byte型数组对象)
    
    例子
        public class Server {
      
      		public static void main(String[] args) {
      			// 创建ServerSocket
      			ServerSocket ss =null;
      			Socket soc=null;
      			InputStream is=null;
      			BufferedReader br =null;
      			OutputStream os=null;
      			try {
      				ss = new ServerSocket(10088);
      				//侦听客户端的请求
      				soc=ss.accept();
      				//获取输入流接收客户端的请求信息
      				is=soc.getInputStream();
      				br = new BufferedReader(new InputStreamReader(is));
      				
      					String str;
      					while((str=br.readLine())!=null){
      						System.out.println("这里是服务器端,接收到的客户端信息为:"+str);
      					}
      					
      					//获取输出流向客户端发送响应信息
      					os=soc.getOutputStream();
      					String str2 = "用户名和密码正确,登录成功";
      					byte[] bytes = str2.getBytes();
      					os.write(bytes);
      					
      				} catch (IOException e) {
      					e.printStackTrace();
      				}finally{
      					try {
      						os.close();
      						br.close();
      						is.close();
      						soc.close();
      						ss.close();
      					} catch (IOException e) {
      						// TODO Auto-generated catch block
      						e.printStackTrace();
      					}
      				}
      			}
      		}
    

单个对象通信TCP

  • LoginClient
        	建立客户端连接	new Socket("localhost",端口号)
        	打开输出流 		new Socket("localhost",端口号).getOutputStream()
        	对象序列化		new ObjectOutputStream(new Socket("localhost",端口号).getOutputStream())
        	发送客户端信息,即向输出流中写入信息
        					User user = new User("Tom",123)
        					new ObjectOutputStream(new Socket.getOutputStream()).writeObject(user)
        	关闭输出流	    new Socket("localhost",端口号).shutdownOutput()
        	
        	接受服务端相应,即从输入流中读取信息
        			new Socket("localhost",端口号).getInputStream()
        			new BufferedReader(new InputStreamReader(new Socket("localhost",端口号).getInputStream())
        	
    
        			
    例子
      		public static void main(String[] args) {
      			Socket socket = null;
      			OutputStream os = null;
      			ObjectOutputStream oos = null;
      			InputStream is = null;
      			BufferedReader br = null;
      			try {
      				// 建立客户端Socket连接,指定服务器的位置为本机以及端口为8800
      				socket = new Socket("localhost", 8800);
      				// 打开输出流
      				os = socket.getOutputStream();
      				// 对象序列化 
      				oos = new ObjectOutputStream(os);
      				// 发送客户端信息,即向输出流中写入信息
      				User user = new User("Tom", "123456");
      				oos.writeObject(user);
      				socket.shutdownOutput();
      	
      				// 接收服务器端的响应,即从输入流中读取信息
      				is = socket.getInputStream();
      				br = new BufferedReader(new InputStreamReader(is));
      				String reply;
      				while ((reply = br.readLine()) != null) {
      					System.out.println("我是客户端,服务器的响应为:" + reply);
      				}
      			} catch (UnknownHostException e) {
      				e.printStackTrace();
      			} catch (IOException e) {
      				e.printStackTrace();
      			} finally {
      				try {
      					br.close();
      					is.close();
      					oos.close();
      					os.close();
      					socket.close();
      				} catch (IOException e) {
      					e.printStackTrace();
      				}
      	
      			}
      		}
      	}
    
  • LoginServer
    建立服务器 			new ServerSocket(端口号);
    等待客户端发起通信	new ServerSocket(端口号).accept()
    打开输入流			new ServerSocket(端口号).accept().getInputStream()
    反序列化				new ObjectInputStream(new ServerSocket().accept().getInputStream())
    从输入流中读取信息	
    		  new ObjectInputStream(new ServerSocket().accept().getInputStream()).readObject()
    
    给客户端一个相应
      		  new ServerSocket(端口号).accept().getOutputStream()
    		  new ServerSocket(端口号).accept().getOutputStream().write(byte型数组对象)
    		 
    例子
        public class LoginServer {
    
      		public static void main(String[] args) {
      			ServerSocket serverSocket = null;
      			Socket socket = null;
      				InputStream is = null;
      				ObjectInputStream ois = null;
      				OutputStream os = null;
      				try {
      					// 建立一个服务器Socket(ServerSocket),指定端口8800并开始监听
      					serverSocket = new ServerSocket(8800);
      					// 使用accept()方法等待客户端发起通信
      					socket = serverSocket.accept();
      					// 打开输入流
      					is = socket.getInputStream();
      					// 反序列化
      					ois = new ObjectInputStream(is);
      					// 获取客户端信息,即从输入流读取信息
      					User user = (User) ois.readObject();
      					if (user != null) {
      						System.out.println("我是服务器,客户登录信息为:" + user.getLoginName() + ","
      								+ user.getPwd());
      					}
      		
      					// 给客户端一个响应,即向输出流中写入信息
      					String reply = "欢迎你,登录成功";
      					os = socket.getOutputStream();
      					os.write(reply.getBytes());
      				} catch (IOException e) {
      					e.printStackTrace();
      				} catch (ClassNotFoundException e) {
      					e.printStackTrace();
      				} finally {
      					// 关闭资源
      					try {
      						os.close();
      						ois.close();
      						is.close();
      						socket.close();
      						serverSocket.close();
      					} catch (IOException e) {
      						e.printStackTrace();
      					}
      				}
      			}
      		}
    
  • User
      	  public class User implements Serializable {
      
      			private static final long serialVersionUID = 1L;
      			/** 用户名 */
      			private String loginName;
      			/** 用户密码 */
      			private String pwd;
      		
      			public User() {
      				super();
      			}
      		
      			public User(String loginName, String pwd) {
      				super();
      				this.loginName = loginName;
      				this.pwd = pwd;
      			}
      		
      			public String getLoginName() {
      				return loginName;
      			}
      		
      			public void setLoginName(String loginName) {
      				this.loginName = loginName;
      			}
      		
      			public String getPwd() {
      				return pwd;
      			}
      		
      			public void setPwd(String pwd) {
      				this.pwd = pwd;
      			}
      		}
    

多个对象通信TCP

  • LoginServer
    建立服务器	new ServerSocket(端口号)
    while死循环进行监听		
    			new ServerSocket(端口号).accept()  --返回的是Socket类型对象
    			把此对象传给loginThread类处理
    
    例子
      		  public class LoginServer {
      		
      				public static void main(String[] args) {
      					
      					ServerSocket serverSocket = null;
      					try {
      						// 建立一个服务器Socket(ServerSocket)指定端口并开始监听
      						serverSocket = new ServerSocket(8800);
      			
      						// 监听一直进行中
      						while (true) {
      							// 使用accept()方法等待客户发起通信
      							Socket socket = serverSocket.accept();
      							LoginThread loginThread = new LoginThread(socket);
      							loginThread.start();
      						}
      					} catch (IOException e) {
      						e.printStackTrace();
      					}
      				}
      			}
    
  • LoginThread(使用多线程处理每监听一个生成一个socket对象)
    
    Socket对象实例化之后可以使用socket
    调用打开输入流getInputStream()   ---返回的是InputStream类型的对象
     
    反序列化
    	new ObjectInputStream(socket.getInputSteam()) 
    
    获取客户端信息
      	new ObjectInputStream(socket.getInputSteam()).readObject()
    
    
    例子
    		public class LoginThread extends Thread {
      			/*
      			 * 示例03:升级示例02,实现多客户端的响应处理。
      			 * 
      			 * 分析如下:
      			 * 	(1)创建服务器端线程类,run()方法中实现对一个请求的响应处理。
      			 * 	(2)修改服务器端代码,让服务器端Socket一直处于监听状态。
      			 * 	(3)服务器端每监听到一个请求,创建一个线程对象并启动
      			 */
      			
      			Socket socket = null;
      			//每启动一个线程,连接对应的Socket
      		
      			public LoginThread(Socket socket) {
      				this.socket = socket;
      			}
      			
      			//启动线程,即响应客户请求
      			public void run() {
      				InputStream is = null;
      				ObjectInputStream ois = null;
      				OutputStream os = null;
      				try {
      					//打开输入流
      					is = socket.getInputStream();
      					//反序列化
      					ois = new ObjectInputStream(is);
      					//获取客户端信息,即从输入流读取信息
      					User user = (User)ois.readObject();
      					if(user!=null){
      						System.out.println("我是服务器,客户登录信息为:"+user.getLoginName()+","+user.getPwd());
      					}
      					
      					//给客户端一个响应,即向输出流中写入信息
      					os = socket.getOutputStream();
      					String reply = "欢迎你,登录成功";
      					os.write(reply.getBytes());
      				} catch (IOException e) {
      					e.printStackTrace();
      				} catch (ClassNotFoundException e) {
      					e.printStackTrace();
      				}finally{
      					try {
      						os.close();
      						ois.close();
      						is.close();
      						socket.close();
      					} catch (IOException e) {
      						e.printStackTrace();
      					}
      				}
      			}
      		}
    
  • LoginClient	
         只要改变	User user = new User("Tom", "123456");就可以模仿多个客户端
    
      	  public class LoginClient01 {
      		
      			/*
      			 * 示例03:升级演示示例02,实现多客户端的响应处理
      			 */
      			public static void main(String[] args) {
      				
    
    
      				Socket socket = null;
      				OutputStream os = null;
      				ObjectOutputStream oos = null;
      				InputStream is = null;
      				BufferedReader br = null;
      				try {
      					// 建立客户端Socket连接,指定服务器的位置为本机以及端口为8800
      					socket = new Socket("localhost", 88100);
      					// 打开输出流
      					os = socket.getOutputStream();
      					// 对象序列化
      					oos = new ObjectOutputStream(os);
      					// 发送客户端信息,即向输出流中写入信息
      					User user = new User("Tom", "123456");
      					oos.writeObject(user);
      					socket.shutdownOutput();
      		
      					// 接收服务器端的响应,即从输入流中读取信息
      					is = socket.getInputStream();
      					br = new BufferedReader(new InputStreamReader(is));
      					String reply;
      					while ((reply = br.readLine()) != null) {
      						System.out.println("我是客户端,服务器的响应为:" + reply);
      					}
      				} catch (UnknownHostException e) {
      					e.printStackTrace();
      				} catch (IOException e) {
      					e.printStackTrace();
      				} finally {
      					try {
      						br.close();
      						is.close();
      						oos.close();
      						os.close();
      						socket.close();
      					} catch (IOException e) {
      						e.printStackTrace();
      					}
      		
      				}
      			}
      		
      		}
    

单向通信UDP

  • 创建DatagramPacket对象,准备接收封装的数据。
      			DatagramPacket  dp = new DatagramPacket(new byte[1024], 1024);
    创建DatagramSocket对象,接收数据保存于DatagramPacket对象中
    		    DatagramSocket ds = new DatagramSocket(8800)
    		    ds.receive(dp)
    利用DatagramPacket对象处理数据
    		  String mess = new String(dp.getData(), 0, dp.getLength())
    
    
    
        模拟客户咨询问题,实现发送方发送咨询问题,接收方接收并显示发送来的咨询问题。
        public class Receive {
      
      	public static void main(String[] args) {
      		/*
      		 * 示例05:模拟客户咨询问题,实现发送方发送咨询问题,接收方接收并显示发送来的咨询问题。
      		 * 
      		 * 接收方实现步骤如下:
      		 * 	(1)创建DatagramPacket对象,准备接收封装的数据。
      		 * 	(2)创建DatagramSocket对象,接收数据保存于DatagramPacket对象中。
      		 * 	(3)利用DatagramPacket对象处理数据。
      		 */
      		
      		DatagramSocket ds = null;
      		//创建DatagramPacket对象,用来准备接收数据
      		byte[] buf = new byte[1024];
      		DatagramPacket  dp = new DatagramPacket(buf, 1024);
      		try {
      			//创建DatagramSocket对象,接收数据
      			ds = new DatagramSocket(8800);
      			ds.receive(dp);
      			//显示接收到的信息
      			String mess = new String(dp.getData(), 0, dp.getLength());
      			System.out.println(dp.getAddress().getHostAddress()+"说:"+mess);
      			
      		} catch (SocketException e) {
      			e.printStackTrace();
      		} catch (IOException e) {
      			e.printStackTrace();
      		}finally{
      			ds.close();
      		}
      	}
      }		
    
  • Send
    
      		 获取本地主机的InetAddress对象。
      		 		InetAddress  ia = InetAddress.getByName("localhost");
      		 创建DatagramPacket对象,封装要发送的信息。
      		 		DatagramPacket dp = new DatagramPacket(mess.getBytes(), mess.getBytes().length, ia, 8800);
      		 利用DatagramSocket对象将DatagramPacket对象数据发送出去。
      		 		DatagramSocket ds = new DatagramSocket();
      				ds.send(dp);
      				
    例子
      	public class Send {
      		public static void main(String[] args) {
      			DatagramSocket ds = null;
      			InetAddress ia = null;
      			String mess = "你好,我想咨询一个问题。";
      			try {
      				//获取本地主机地址
      				ia = InetAddress.getByName("localhost");
      				//创建DatagramPacket对象,封装数据
      				DatagramPacket dp = new DatagramPacket(mess.getBytes(), mess.getBytes().length, ia, 8800);
      				//创建DatagramSocket对象,向服务器发送数据
      				ds = new DatagramSocket();
      				ds.send(dp);
      					
      			} catch (UnknownHostException e) {
      				e.printStackTrace();
      			} catch (SocketException e) {
      				e.printStackTrace();
      			} catch (IOException e) {
      				e.printStackTrace();
      			}finally{
      				ds.close();
      			}	
      		}		
      	}
    

双向通信UDP

  • Receive
    
    
      	 public class Receive {
      
      		public static void main(String[] args) {
      			/*
      			 * 示例06:升级示例05,发送方发送咨询问题,接收方回应咨询。
      			 * 
      			 * 接收方实现步骤如下: 
      			 * (1)创建DatagramPacket对象,准备接收封装的数据。
      			 * (2)创建DatagramSocket对象,接收数据保存于DatagramPacket对象中。
      			 * (3)利用DatagramPacket对象处理数据。
      			 */
      	
      			DatagramSocket ds = null;
      			DatagramPacket dp = null;
      			DatagramPacket dpto = null;
      			// 创建DatagramPacket对象,用来准备接收数据
      			byte[] buf = new byte[1024];
      			dp = new DatagramPacket(buf, 1024);
      			try {
      				// 创建DatagramSocket对象,接收数据
      				ds = new DatagramSocket(8800);
      				ds.receive(dp);
      				// 显示接收到的信息
      				String mess = new String(dp.getData(), 0, dp.getLength());
      				System.out.println(dp.getAddress().getHostAddress() + "说:" + mess);
      				
      //向客户端发送响应信息
      				String reply = "你好,我在,请咨询!";
      				// 显示与本地对话框
      				System.out.println("我  说:" + reply);
      				// 创建DatagramPacket对象,封装数据
      				SocketAddress sa = dp.getSocketAddress();
      				dpto = new DatagramPacket(reply.getBytes(),
      						reply.getBytes().length, sa);
      				ds.send(dpto);
      				
      			} catch (SocketException e) {
      				e.printStackTrace();
      			} catch (IOException e) {
      				e.printStackTrace();
      			} finally {
      				ds.close();
      			}
      		}
      	}
    
  • Send
      		public class Send {
      			/*
      			 * 示例06:升级示例05,发送方发送咨询问题,接收方回应咨询。
      			 * 
      			 * 发送方实现步骤如下: 
      			 * (1)获取本地主机的InetAddress对象。 
      			 * (2)创建DatagramPacket对象,封装要发送的信息。
      			 * (3)利用DatagramSocket对象将DatagramPacket对象数据发送出去。
      			 */
      		
      			public static void main(String[] args) {
      				DatagramSocket ds = null;
      				InetAddress ia = null;
      				String mess = "你好,我想咨询一个问题。";
      				System.out.println("我说:" + mess);
      				try {
      					// 获取本地主机地址
      					ia = InetAddress.getByName("localhost");
      					// 创建DatagramPacket对象,封装数据
      					DatagramPacket dp = new DatagramPacket(mess.getBytes(),
      							mess.getBytes().length, ia, 8800);
      					// 创建DatagramSocket对象,向服务器发送数据
      					ds = new DatagramSocket();
      					ds.send(dp);
      					
      //接受服务端发送的信息
      					byte[] buf = new byte[1024];
      					DatagramPacket dpre = new DatagramPacket(buf, buf.length);
      					ds.receive(dpre);
      					// 显示接收到的信息
      					String reply = new String(dpre.getData(), 0, dpre.getLength());
      					System.out.println(dpre.getAddress().getHostAddress() + "说:"
      							+ reply);
      				
      				} catch (UnknownHostException e) {
      					e.printStackTrace();
      				} catch (SocketException e) {
      					e.printStackTrace();
      				} catch (IOException e) {
      					e.printStackTrace();
      				} finally {
      					ds.close();
      				}
      			}
      		}
    

XML

  • 什么是XML?
      	它是一个可扩展标记语言
    作用
      	数据交互、配置应用程序和网站、Ajax基石
    特点
      	XML与操作系统、编程语言的开发平台无关
      	实现不同系统之间的数据交互					
    
  • XML常用的两种解析技术
      DOM
      	DOM是基于XML的树结构来完成解析的,DOM解析XML文档时,会根据读取的文档,构建一个驻留在内存的树结构,然后就可以使用DOMAPI来操作这个结构。
      	因为整个文档的树结构是驻留在内存中的,所以非常方便于各种操作,支持删除、修改、重新排列等多种功能。
      	DOM解析XML的方式非常适用于多次访问XML的程序,但是DOM解析比较消耗资源。
      	
      DOM4J
      	DOM4J是一个非常优秀的Java XML API,具有性能优异、功能强大和易用的特点,同时它也是一个开源库。
      	DOM4J用于在Java平台上使用Java集合框架处理XML、XPath和XSLT,并与DOM、SAX和JAXP完成集合。
      	DOM4J大量使用接口,面向接口编程是它比JDOM更加灵活。如今越来越多的Java软件都使用DOM4J来读写XML,特别值的一提的是Sum的JAXM也在使用DOM4J。
    

DOM解析技术

  •   前沿知识
      		获得集合、节点数组、数组、字符串长度
      			集合 		-----size()
      			节点数组		-----getLength()
      			数组		-----length
      			字符串		-----length()
      			
      		获得集合、节点数组中的元素(下标从0开始)
      			集合 		
      				ArrayList	-----get(i)
      				LinkedList 	-----get(i)、getFirst()、getLast()
      				HashMap		-----get("key")
      				HashSet		-----无get()方法
      			节点数组(NodeList)		-----item(i) 
      		
    
    
      要想将XML文件转换成Document对象,需要使用到解析器对象
      要想使用解析器对象将xml文件转换成Document对象,首先需要使用解析器工厂对象
      1.获取解析器对象
      		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      2.使用解析器工厂对象获得解析器对象
      		DocumentBuilder db =dbf.newDocumentBuilder();
      3.使用解析器对象将xml文件转换成Document对象
      		Document document = db.parse("src/com/bdqn/demo02/demo.xml");
      4.获取xml中你需要获取标签的名字(student标签有可能不止一对,所以返回的是节点数组),返回值是NodeList
      		NodeList nl = document.getElementsByTagName("student");
      ---------------------------------------------------------------------------------
      5.Element接口中的方法
      		getAttribute("属性名")		通过元素节点的属性名称获取属性的值
      		getChildNodes()				获取该节点的子节点,返回的是一个子节点数组	
      		setAttribute("属性名称", "属性的值");  设置元素节点的属性名称和设置该属性的值
      6.Document接口中的方法
      		getElementsByTagName("属性名称")		通过标签名获取该属性名称的节点数组
      		createElement("属性名称")			创建新的节点
      7.为什么需要保存XML文件保存XML文件?
      		因为所有的操作都是在内存中操作的,在内存中操作完成之后需要把内存中的数据写入到外存中,一定要把数据保存起来
      	
    查看
      public class Demo01 {
      		public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
    
    
      			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      			DocumentBuilder db =dbf.newDocumentBuilder();
      			Document document = db.parse("src/com/bdqn/demo02/demo.xml");
      			NodeList nl = document.getElementsByTagName("student");	
      			
      			for (int i = 0; i < nl.getLength(); i++) {
      				//将节点集合中的元素取出来
      				Node node = nl.item(i);
      				Element student = (Element)node;
      				String s = student.getAttribute("studId");   //getAttribute()方法通过元素节点的属性名称获取属性的值
      				System.out.println(s);
      				
      				//获取studId中的子节点
      				//NodeList是节点的列表
      				NodeList typeNodes = student.getChildNodes();  //一个类实现了一个接口,这个接口的实例化(得到的实例化,自身不能实例化)调用这个方法
      				for(int j=0;j  
      	
      		
      		张三
      		19
      		
      	
      		
      	
      		李四
      		19
      		
      		
      	
      	
    
    注意
      	  使用getChildNodes()会将空白符也作为子元素添加进去,所以getChildNodes().item(i)的时候,有些子节点是空白符
      	  这时候要加if判断一下,过滤掉空白符,有两种写法
      		   Node childNode=getChildNodes().item(i);
      		   第一种
      			  if(childNode instanceof Element){
      			        //具体执行代码
      			    }
      		     
      		   第二种
      		 	 if(childNode.getNodeType()==Node.ELEMENT_NODE){
      		        //具体执行代码
      		    }
      	    
      	    
      	    空白字符,也可简称“空白符”,通俗理解,就是不会显示出来的字符,类似空格符、回车换行符、制表符之类的字符,从视觉效果上来看,只是一个空白区域而已。
      	    可以把demo01.xml写成一行,不要留有空格,可以不写if判断语句
      	    
      		当既不写if又不把xml写成一行会报异常
      		    Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.DeferredTextImpl cannot be cast to org.w3c.dom.Element
      	  	 	Element type =(Element)typeNode;  空白字节点不能强转成Element,因为它们不是父子类,所以就会显示类型转换异常 
      
      	
    
      	  	解释typeNode.getNodeType()==Node.ELEMENT_NODE
      			typeNode是节点的意思,那么它可能是文字内容、CDATA段、元素、属性等等,具体是什么,就要靠NodeType来判断节点的类型。
      			ELEMENT_NODE是一个枚举值,代表元素节点类型。
      			所以if(node.getNodeType()==Node.ELEMENT_NODE)的意思就是:如果当前节点是元素节点的话。
    
    增加				
      public class ParseXMLDemo {
      
      	//在XML文档中添加品牌为“MOTO”,型号为“A1680”的手机收藏信息
      	public static void main(String[] args) throws SAXException, IOException, ParserConfigurationException, TransformerException {
      		
      		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      		DocumentBuilder db = dbf.newDocumentBuilder();
      		Document document = db.parse("src/com/bdqn/demo03/收藏信息2.xml");
      		
      		//创建Brand节点
      		Element brandElement =document.createElement("Brand");
      		brandElement.setAttribute("name", "MOTO");  //setAttribute()方法设置元素节点的属性名称和设置该属性的值
      		//创建Brand节点的子节点Type节点
      		Element typeElement =document.createElement("Type");
      		typeElement.setAttribute("name", "A1680");
      		//添加这两个节点的父子关系,以及父节点和它的父节点,直到到最后层祖节点为止
      		brandElement.appendChild(typeElement);
      		Element phoneElement =(Element) document.getElementsByTagName("PhoneInfo").item(0);
      		phoneElement.appendChild(brandElement);
      		
      		//保存XML文件,因为上面的操作都是在内存中操作的,在内存中操作完成之后一定要把数据保存起来
      		TransformerFactory transformerFactory = TransformerFactory.newInstance();
      		Transformer transformer = transformerFactory.newTransformer();	
      		//设置编码格式
      		transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8");	
      		//Source(接口)和Result(接口),使用它们的实现类
      		DOMSource domSource = new DOMSource(document);
      		StreamResult result = new StreamResult(new FileOutputStream("收藏信息2.xml"));
      		//把DOM转换成XML文件
      		transformer.transform(domSource,result);
      		System.out.println("数据添加成功");
      	}
      }
      
      
    删除
      public class ParseXMLDemo {
      	//从保存手机收藏信息的XML文档中,删除手机品牌信息“摩托罗拉”
      	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, TransformerException {
      
      			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      			DocumentBuilder db = dbf.newDocumentBuilder();
      			Document document = db.parse("src/com/bdqn/demo05/收藏信息4.xml");
      			
      			
      			//找到删除的节点
      			NodeList list = document.getElementsByTagName("Brand");   //通过标签名获取元素的节点,在通过item(下标)方法找到具体的节点(这里需要把Node强转成Element,Element是继承Node),强转原因是要使用getAttribute()方法
      			for (int i = 0; i < list.getLength(); i++) {
      				Element brandElement = (Element)list.item(i);
      				String brandName = brandElement.getAttribute("name");
      				if (brandName.equals("摩托罗拉")) {
      					brandElement.getParentNode().removeChild(brandElement);  //强转后的子节点找父节点移除子节点
      				}
      			}
      			//保存XML文件
      			TransformerFactory transformerFactory = TransformerFactory.newInstance();
      			Transformer transformer = transformerFactory.newTransformer();
      			DOMSource domSource = new DOMSource(document);
      			//设置编码类型
      			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
      			StreamResult result = new StreamResult(new FileOutputStream("收藏信息4.xml"));
      			//把DOM转换为XML文件
      			transformer.transform(domSource, result);
      			System.out.println("删除元素完毕");
      	}
      
      }
    
    
    修改
      public class ParseXMLDemo {
      	//将保存手机收藏信息的XML文档中的手机品牌信息MOTO修改为“摩托罗拉”。
      	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, TransformerException {
      	
      		DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
      		DocumentBuilder db = dbf.newDocumentBuilder();
      		Document document = db.parse("src/com/bdqn/demo04/收藏信息3.xml");
      		
      		//找到修改的节点
      		NodeList list = document.getElementsByTagName("Brand");
      		for(int i=0;i
          
              
              
              
          
          
              
          
          
          	
          
      
    

DOM4J

  •   public class Dom4j {
      
      		public static Document document;
      		
      		public static void main(String[] args) {
      			loadDocument();
      	//		showPhoneInfo();
      			addNewPhoneInfo();
      	//		saveXML("新收藏.xml");
      	//		updatePhoneInfo();
      	//		deleteItem();
      			showPhoneInfo();
      		}
      		
      (获取操作对象document)		
      		public static void loadDocument(){
      			try{
      				SAXReader saxReader = new SAXReader();
      				document = saxReader.read(new File("收藏信息.xml"));
      			}catch (Exception e) {
      				// TODO: handle exception
      				e.printStackTrace();
      			}
      		}
      (更新操作)
      		public static void updatePhoneInfo(){
      			// 获取XML的根节点
      			Element root = document.getRootElement();
      			int id = 0;
      			for (Iterator itBrand = root.elementIterator(); itBrand.hasNext();) {
      				Element brand = (Element) itBrand.next();
      				id++;
      				brand.addAttribute("id", id + "");
      				brand.addAttribute("name","大家都是华为,666");
      			}
      			saveXML("收藏信息.xml");
      		}
      (删除操作)
      		public static void deleteItem(){
      			// 获取XML的根节点
      			Element root = document.getRootElement();
      			int id = 0;
      			for (Iterator itBrand = root.elementIterator(); itBrand.hasNext();) {
      				Element brand = (Element) itBrand.next();
      				if (brand.attributeValue("name").equals("华为")) {
      					brand.getParent().remove(brand);
      				}
      			}
      			saveXML("收藏信息.xml");			
      		}
      (输出操作)
      		public static void showPhoneInfo() {
      			// 获取XML的根节点
      			Element root = document.getRootElement();
      			// 遍历所有的Brand标签
      			for (Iterator itBrand = root.elementIterator(); itBrand.hasNext();) {
      				Element brand = (Element) itBrand.next();
      				// 输出标签的name属性
      				System.out.print("品牌:" + brand.attributeValue("name"));
      				// 遍历Type标签
      				for (Iterator itType = brand.elementIterator(); itType.hasNext();) {
      					Element type = (Element) itType.next();
      					// 输出标签的name属性
      					System.out.println("\t型号:" + type.attributeValue("name"));
      				}
      			}
      		}
      (保存操作)		
      		public static void saveXML(String path){
      			try {
      				OutputFormat format = OutputFormat.createPrettyPrint();
      				format.setEncoding("GBK"); // 指定XML编码
      				XMLWriter writer;
      				writer = new XMLWriter(new FileWriter(path), format);
      				writer.write(document);
      				writer.close();
      			} catch (IOException e) {
      				// TODO Auto-generated catch block
      				e.printStackTrace();
      			}
      		}
      (增加操作)
      		public static void addNewPhoneInfo(){
      			// 获取XML的根节点   
      			Element root = document.getRootElement();		//根节点
      			// 创建Brand标签
      			Element el = root.addElement("Brand");			//父节点
      			// 给Brand标签设置属性
      			el.addAttribute("name", "三");
      			// 创建Type标签
      			Element typeEl = el.addElement("Type");			//子节点
      			// 给Type标签设置属性
      			typeEl.addAttribute("name", "Note4");
      			saveXML("收藏信息.xml");
      		}
      	}
    

你可能感兴趣的:(java,开发语言)