Java学习笔记
2017-01-25 11:57
375 查看
String
public class Test { public static void main(String[] args) { String str = "agbdfgadda"; //1.是否以指定字符串开头 boolean flag = str.startsWith("agbd"); //true System.out.println(flag); //2.是否包含另一个字符串 flag = str.contains("dda"); //true System.out.println(flag); int index = str.indexOf("cf"); if(index == -1) //not contains System.out.println("not contains"); //3.字符串中出现另一个字符串的位置 index = str.indexOf("bdf"); //2 System.out.println(index); //4.将指定位置的字符串替换为另一个字符串 String after = str.replace("dda", "demo"); //agbdfgademo System.out.println(after); //5.将字符串比较大小,String类实现了comparable接口,所以有了compareTo方法,可以比较 String compareStr = "ab"; int result = str.compareTo(compareStr); //负数小于,0等于,正数大于 //5 System.out.println(result); //6.将字符串转换为字符数组或者字节数组 char[] chars = str.toCharArray(); //agbdfgadda System.out.println(chars); byte[] bytes = str.getBytes(); //7.转成大小写 String upperString = str.toUpperCase(); String lowerString = str.toLowerCase(); //AGBDFGADDA System.out.println(upperString); //8.将字符串按照指定方式分解成多个字符串 str = "lisi,wangwu,zhaoliu"; String[] names = str.split(","); //lisi //wangwu //zhaoliu for(int i=0; i<names.length; i++) System.out.println(names[i]); } }
public class Test { public static void main(String[] args) { /* * 对字符串数组进行排序 */ String[] str = {"abc","nba","abb","zzz"}; Arrays.sort(str); //abb abc nba zzz for(int i=0; i<str.length; i++) System.out.println(str[i]); } }
public class Test { public static void main(String[] args) { /* * 查找一个字符串中含有多少子串 */ String str = "adgvdfcfdgdfswcfdfkcdcf"; String key = "cf"; int index = 0; int count = 0; while((index = str.indexOf(key, index)) != -1) { index += key.length(); count++; } //3 System.out.println(count); } }
Comparable(接口)
public class Person implements Comparable { private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } /* * 名字和年龄相同即认为相同 */ @Override public boolean equals(Object obj) { if(this == obj) return true; if(!(obj instanceof Person)) throw new ClassCastException("类型错误"); Person p = (Person)obj; return this.name.equals(p.name) && this.age == p.age; } /* * 按年龄大小排序 */ @Override public int compareTo(Object o) { if(!(o instanceof Person)) throw new ClassCastException("类型错误"); Person p = (Person)o; // if(this.age > p.age) // return 1; // else if(this.age < p.age) // return -1; // return 0; return this.age - p.age; } }
StringBuffer(容器)
public class Test { public static void main(String[] args) { /* * StringBuffer操作 */ StringBuffer buffer = new StringBuffer(); buffer.append("dsf").append("woca"); buffer.insert(1, true); //dtruesfwoca System.out.println(buffer); buffer.replace(0, 4, "bbb"); //bbbesfwoca System.out.println(buffer); String str = "a" + "b" + "c"; //底层为buffer.append("a").append("b").append("c").toString(); } }
StringBuffer和StringBuilder的区别
StringBuilder:非同步,单线程访问效率高StringBuffer:同步的,多线程访问安全(适用多个线程对缓
20000
冲区进行append,delete,insert等操作)
System
不需要实例化,都是静态的属性和方法out对应标准输出流(显示器)
in对应的是键盘
public class SystemDemo { //方便移植 private static final String LINE_SEPARATOR = System.getProperty("line.separator"); public static void main(String[] args) { /* * System类演示 */ //当前时间到1970年1月1日午夜之间的时间差,以毫秒为单位测量,将开始时间和结束时间相减,可以得出程序的运行时间 long time = System.currentTimeMillis(); //1487856430296 System.out.println(time); //太多了,简单举几个例子 //java.runtime.name::Java(TM) SE Runtime Environment //sun.boot.library.path::C:\Program Files\Java\jre1.8.0_101\bin //java.vm.version::25.101-b13 Properties prop = System.getProperties(); Set<String> keySet = prop.stringPropertyNames(); for (String key : keySet) { String value = prop.getProperty(key); System.out.println(key + "::" + value); } //获取指定信息,比如操作系统 String osname = System.getProperty("os.name"); //Windows 7 System.out.println(osname); //获取系统中的行分隔符,这样该程序在移植时,很方便,不同的系统,获取该系统上行分隔符 //例如回车换行在windows上是/r/n在linux上是/n //hello //world System.out.println("hello" + LINE_SEPARATOR + "world"); } }
Math
public class MathDemo { public static void main(String[] args) { /* * Math方法都是静态的 */ //获取参数右边的整数 double d1 = Math.ceil(12.54); //获取参数左边的整数 double d2 = Math.floor(12.54); //四舍五入 double d3 = Math.round(12.54); //13.0 System.out.println(d1); //12.0 System.out.println(d2); //13.0 System.out.println(d3); //返回a的b次方 //1000.0 System.out.println(Math.pow(10, 3)); //产生1到6的随机数,random方法产生的是[0.0,1.0)范围内的随机数 int num1 = (int)(Math.random() * 6 + 1); double num2 = Math.ceil(Math.random() * 6); Random r = new Random(); int num3 = r.nextInt(6) + 1; } }
集合框架
List-有序的,带索引的,通过索引就可以精确的操作集合中元素,元素是可以重复的,List提供了增删改查动作,新出的子类都是以List结尾的,通常都是非同步的Vector,可以增长的数组结构,同步的
ArrayList,是数组结构,长度是可变的,原理是创建新数组+复制数组。查询速度很快,增删较慢,不同步的
LinkedList,是链表结构,不同步的,增删速度很快,查询速度较慢,可用于实现堆栈,队列
Set -不包含重复元素的集合,不保证顺序。而且方法和Collection一致,Set集合取出元素的方式只有一种,迭代器
HashSet,哈希表结构,不同步,保证元素唯一性的方式依赖于:hashCode(),equals()方法
TreeSet,可以对Set集合中的元素进行排序,使用的是二叉树结构,保证元素唯一性的方法:使用对象的比较方法是0,视为相同元素不存,元素的排序比较有两种方式:
1.元素自身具备自然排序,其实就是实现了Comparable接口重写了compareTo方法。如果元素自身不具备自然排序,或 者具备的自然排序不是所需要的,这时只能用第二种方式
2.比较器排序,其实就是在创建TreeSet集合时,在构造函数中指定具体的比较方式。需要定义一个类实现Comparator 接口,重写compare方法
到此为止,在往集合中存储对象时,通常对该对象都需要覆盖hashCode,equals,同时实现Comparable接口,建立对象的自然排序,通常还有一个方法也会复习toString()
Map -内部存储的都是键值对,必须要保证键的唯一性
Hashtable:哈希表,是同步的,不允许null最为键和值。被HashMap替代
Properties:属性集,键和值都是字符串,而且可以结合流进行键值的操作
HashMap:哈希表,不是同步的,允许null作为键和值
LinkedHashMap:基于链表+哈希表。可以保证map集合有序(存入和取出的顺序一致)
TreeMap:二叉树,不是同步的,可以对map集合中的键进行排序
Collection(集合框架接口)
public class Test { public static void main(String[] args) { /* * Collection一般方法演示 */ Collection coll = new ArrayList<>(); //添加 coll.add("item1"); coll.add("item2"); //[item1, item2] System.out.println(coll); //删除 coll.remove("item2"); //[item1] System.out.println(coll); //判断是否包含 //true System.out.println(coll.contains("item1")); //清楚元素 coll.clear(); //[] System.out.println(coll); } }
public class Test { public static void main(String[] args) { /* * Collection带all方法演示 */ Collection c1 = new ArrayList(); Collection c2 = new ArrayList(); Collection c3 = new ArrayList(); c1.add("1"); c1.add("2"); c1.add("3"); c2.add("1"); c2.add("5"); c2.add("6"); c3.add("1"); c3.add("2"); c3.add("1"); c1.addAll(c2); //c1 = [1, 2, 3, 1, 5, 6] System.out.println("c1 = " + c1); //true System.out.println(c1.containsAll(c3)); //删除c1中和c3相同的元素 c1.removeAll(c3); //[3, 5, 6] System.out.println(c1); //保留c1中和c2相同的元素 c1.retainAll(c2); //[5, 6] System.out.println(c1); } }
Iterator(接口,迭代器,用来取出集合中的元素)
public class Test { public static void main(String[] args) { /* * Iterator方法演示 */ Collection coll = new ArrayList(); //存储的是对象的引用 coll.add("item1"); coll.add("item2"); //可以这么写,但是存储的还是对象(基本数据类型的包装类) //coll.add(3); //获取容器的迭代器对象,通过iterator方法 Iterator it = coll.iterator(); //item1 //item2 while(it.hasNext()) { System.out.println(it.next()); } //5 //5 //循环结束it2就直接消失了,而上面一种不会消失 for(Iterator it2 = coll.iterator(); it2.hasNext();) { //存储时提升为Object类型 Object obj = it2.next(); String str = (String)obj; System.out.println(str.length()); } } }
List(接口)
public class Test { public static void main(String[] args) { /* * List方法演示,支持curd,增删改查 */ //添加元素 List list = new ArrayList(); list.add(0); list.add(1); list.add(2); //删除元素 list.remove(0); //修改元素 list.set(1, 7); //获取元素,一种是迭代一种是遍历+get //1 //7 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } }
ListIterator
是一个接口,继承自Iterator,Iterator接口不能在遍历过程中增加和修改,而ListIterator可以,用来遍历和修改List接口例如在迭代过程中如果有Item2则增加Item3
public class Test { public static void main(String[] args) { /* * ListIterator方法演示 */ List list = new ArrayList(); list.add("item1"); list.add("item2"); Iterator it = list.iterator(); while(it.hasNext()) { Object obj = it.next(); if("item2".equals(obj)) list.add("item3"); } System.out.println(list); } }
这种写法会触发java.util.ConcurrentModificationException
应该用下面这种方法
public class Test { public static void main(String[] args) { /* * ListIterator方法演示 */ List list = new ArrayList(); list.add("item1"); list.add("item2"); ListIterator it = list.listIterator(); while(it.hasNext()) { Object obj = it.next(); if("item2".equals(obj)) //也可以修改,即set方法 it.add("item3"); } //[item1, item2, item3] System.out.println(list); } }
LinkedList
public class Test { public static void main(String[] args) { /* * LinkedList方法演示 */ LinkedList link = new LinkedList(); link.addFirst("item1"); link.addFirst("item2"); link.addFirst("item3"); //获取但不删除第一个元素 //item3 System.out.println(link.getFirst()); //返回删除的元素 //item3 System.out.println(link.removeFirst()); //item2 //item1 while(!link.isEmpty()) { System.out.println(link.removeFirst()); } } }
public class Test { public static void main(String[] args) { /* * LinkedList模拟实现队列 */ Queue queue = new Queue(); queue.myAdd("item1"); queue.myAdd("item2"); queue.myAdd("item3"); //item1 //item2 //item3 while(!queue.isNull()) { System.out.println(queue.myGet()); } } } class Queue { private LinkedList link; public Queue() { link = new LinkedList(); } public void myAdd(Object obj) { link.addFirst(obj); } public Object myGet() { return link.removeLast(); } public boolean isNull() { return link.isEmpty(); } }
Set
是一个接口public class Test { public static void main(String[] args) { /* * Set可以用来去重,不一定有序 */ Set set = new HashSet(); set.add("456"); set.add("123"); set.add("123"); //123 //456 for(Iterator it = set.iterator(); it.hasNext(); ) { System.out.println(it.next()); } } }
HashSet
哈希表重复元素存不进去,先看hashcode()是否一致,再判断是否equals(),hascode相同并且equals2个元素相同,是HashMap的一个实例public class Student implements Comparable{ /* * Student对象类往HashSet存储时要重写hashcode和equals方法 * 往TreeSet存储时要继承comparable接口,建立学生的自然排序(对象的默认排序方式) */ private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; //看字节码是否向相同 if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Object o) { if(!(o instanceof Student)) throw new ClassCastException(); Student stu = (Student)o; int temp = this.age - stu.age; return temp == 0 ? this.name.compareTo(stu.name) : temp; } }
public class Test { public static void main(String[] args) { /* * HashSet存储和自定义对象要重写hascode和equals方法 */ Set set = new HashSet(); set.add(new Student("stu1", 10)); set.add(new Student("stu2", 20)); set.add(new Student("stu2", 20)); //Student [name=stu1, age=10] //Student [name=stu2, age=20] for(Iterator it = set.iterator(); it.hasNext(); ) { System.out.println(it.next()); } } }
TreeSet
是TreeMap的一个实例public class Test { public static void main(String[] args) { /* * TreeSet用元素的自然顺序进行排序 */ Set set = new TreeSet(); set.add(new Student("stu1", 10)); set.add(new Student("stu3", 20)); set.add(new Student("stu2", 20)); set.add(new Student("stu2", 20)); //Student [name=stu1, age=10] //Student [name=stu2, age=20] //Student [name=stu3, age=20] for(Iterator it = set.iterator(); it.hasNext(); ) { System.out.println(it.next()); } } }
Comparator
是一个借口,基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。 上面往TreeSet里面存储时是先按年龄后按姓名排序,而如果想先按姓名后按年龄排序就可以这样写public class ComparatorByName implements Comparator { @Override public int compare(Object o1, Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int temp = s1.getName().compareTo(s2.getName()); return temp == 0 ? s1.getAge() - s2.getAge() : temp; } }
public class Test { public static void main(String[] args) { /* * TreeSet用comparator进行排序 */ Set set = new TreeSet(new ComparatorByName()); set.add(new Student("stu2", 10)); set.add(new Student("stu1", 10)); set.add(new Student("stu1", 20)); //Student [name=stu1, age=10] //Student [name=stu1, age=20] //Student [name=stu2, age=10] for(Iterator it = set.iterator(); it.hasNext(); ) { System.out.println(it.next()); } } }
public class ComparatorByLength implements Comparator { @Override public int compare(Object o1, Object o2) { String s1 = (String)o1; String s2 = (String)o2; int temp = s1.length() - s2.length(); return temp == 0 ? s1.compareTo(s2) : temp; } }
public class Test { public static void main(String[] args) { /* * 对字符串进行长度排序,由短到长 */ Set set = new TreeSet(new ComparatorByLength()); set.add("hadf"); set.add("ddf"); set.add("wca"); set.add("dfdfgdf"); //ddf //wca //hadf //dfdfgdf for (Iterator it = set.iterator(); it.hasNext();) System.out.println(it.next()); } }
LinkedHashSet
public class Test { public static void main(String[] args) { /* * 提高唯一性元素的查询效率还想有序,使用HashSet的子类LinkedHashSet */ Set set = new LinkedHashSet(); set.add("ddf"); set.add("wca"); set.add("dfdfgdf"); set.add("aa"); //ddf //wca //dfdfgdf //aa for (Object object : set) { System.out.println(object); } } }
Map
是一个接口public class Test { public static void main(String[] args) { /* * Map基本方法演示 */ Map<String,String> map = new HashMap<String,String>(); map.put("星期一", "mon"); //键相同,值覆盖,并返回旧值 //mon System.out.println(map.put("星期一", "monday")); map.put("星期日", "sunday"); //{星期日=sunday, 星期一=monday} System.out.println(map); //根据键删除键值对,并返回值 //sunday System.out.println(map.remove("星期日")); //{星期一=monday} System.out.println(map); } }
public class Test { public static void main(String[] args) { /* * keySet,entrySet和 values方法演示 */ Map<String,String> map = new HashMap<String,String>(); map.put("星期一", "monday"); map.put("星期二", "tuesday"); Set<String> keySet = map.keySet(); //星期二::tuesday //星期一::monday for (Iterator<String> it = keySet.iterator(); it.hasNext();) { String key = (String) it.next(); String value = map.get(key); System.out.println(key + "::" + value); } //星期二::tuesday //星期一::monday for (String string : keySet) { System.out.println(string + "::" + map.get(string)); } Set<Map.Entry<String, String>> entrySet = map.entrySet(); Iterator<Map.Entry<String, String>> it = entrySet.iterator(); //星期二::tuesday //星期一::monday while(it.hasNext()) { Map.Entry<String, String> me = it.next(); String key = me.getKey(); String value = me.getValue(); System.out.println(key + "::" + value); } //星期二::tuesday //星期一::monday for(Map.Entry<String, String> me : map.entrySet()) { String key = me.getKey(); String value = me.getValue(); System.out.println(key + "::" + value); } Collection<String> values = map.values(); //value::tuesday //value::monday for (String value : values) { System.out.println("value" + "::" + value); } } }
HashMap
根据hashCode和equals判断键值是否相等public class Student implements Comparable<Student>{ /* * 重写hashCode和equals是为了保证HashMapTest里面知道同姓名和同年龄是一个相同的键值 * 实现comparable接口是为了放进TreeSet中的时候进行比较,也是判断键值是否相等的依据 */ String name; int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Student o) { int temp = this.age - o.age; return temp == 0 ? this.name.compareTo(o.name) : temp; } }
public class HashMapTest { public static void main(String[] args) { /* * HashMap存储自定义对象 */ Map<Student,String> map = new HashMap<Student,String>(); map.put(new Student("张三",29), "上海"); map.put(new Student("李四",30), "北京"); map.put(new Student("李四",30), "南京"); //Student [name=张三, age=29]......上海 //Student [name=李四, age=30]......南京 新值替换旧值的结果 for (Student key : map.keySet()) { String value = map.get(key); System.out.println(key.toString() + "......" + value); } } }
HashMap和HashTable的区别
HashTable的方法是同步的,HashMap的方法不同步HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)
HashTable有一个contains()方法,功能和containsValue()一样
HashTable使用Enumeration(),HashMap使用Iterator()
hash数组的初始化大小和增长方式不同
哈希值的使用不同,HashTable直接使用对象的hashCode,而HashMap会重新计算hash值。
TreeMap
根据compareTo判断键值是否相等public class TreeMapTest { public static void main(String[] args) { /* * TreeMap存储自定义对象 */ Map<Student,String> map = new TreeMap<Student,String>(); map.put(new Student("aaa",30), "上海"); map.put(new Student("ddd",35), "北京"); map.put(new Student("ccc",32), "南京"); map.put(new Student("ccc",32), "上海"); map.put(new Student("xxx",27), "太原"); //Student [name=xxx, age=27]::太原 //Student [name=aaa, age=30]::上海 //Student [name=ccc, age=32]::上海 //Student [name=ddd, age=35]::北京 for (Map.Entry<Student, String> me : map.entrySet()) { Student key = me.getKey(); String value = me.getValue(); System.out.println(key + "::" + value); } } }
public class CompatorByName implements Comparator<Student> { /* * 按照姓名排序,定义一个比较器 */ @Override public int compare(Student o1, Student o2) { int temp = o1.getName().compareTo(o2.getName()); return temp == 0 ? o1.age - o2.age : temp; } }
public class TreeMapTest { public static void main(String[] args) { /* * TreeMap存储自定义对象时使用自己定义的比较器 */ Map<Student,String> map = new TreeMap<Student,String>(new CompatorByName()); map.put(new Student("aaa",30), "上海"); map.put(new Student("ddd",35), "北京"); map.put(new Student("ccc",32), "南京"); map.put(new Student("ccc",32), "上海"); map.put(new Student("xxx",27), "太原"); //Student [name=aaa, age=30]::上海 //Student [name=ccc, age=32]::上海 //Student [name=ddd, age=35]::北京 //Student [name=xxx, age=27]::太原 for (Map.Entry<Student, String> me : map.entrySet()) { Student key = me.getKey(); String value = me.getValue(); System.out.println(key + "::" + value); } } }
范型
1安全机制2将运行期间的ClassCastException转移到编译时期变成编译失败
3泛型技术,是给编译器使用的技术
4避免了强转的麻烦
public class TreeSetTest { public static void main(String[] args) { /* * 泛型演示 */ Set<String> set = new TreeSet<String>(); set.add("aaa"); set.add("bbb"); //aaa //bbb for (Iterator<String> it = set.iterator(); it.hasNext();) { String str = it.next(); System.out.println(str); } } }
定义一个工具类对对象进行操作,比如设置和获取,JDK1.5以前是这么干的
public class GenericDemo { public static void main(String[] args) { /* * 没有泛型的做法 */ Tool t = new Tool(); t.setObj("haha"); //会引起ClassCastException //t.setObj(6); String str = (String)t.getObj(); //haha System.out.println(str); } } class Tool { private Object obj; public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } }
泛型类的使用
public class GenericDemo { public static void main(String[] args) { /* * 泛型类的使用 */ Tool<String> t = new Tool<String>(); t.setObj("aa"); //aa System.out.println(t.getObj()); Queue<String> que = new Queue<String>(); que.myAdd("1"); que.myAdd("2"); que.myAdd("3"); //1 //2 //3 while (!que.isNull()) { System.out.println(que.myGet()); } } } //将泛型定义在类上,泛型类 class Tool<Q> { private Q obj; public Q getObj() { return obj; } public void setObj(Q obj) { this.obj = obj; } } class Queue<E> { private LinkedList<E> list; Queue() { list = new LinkedList<E>(); } public void myAdd(E obj) { list.addLast(obj); } public E myGet() { return list.removeFirst(); } public boolean isNull() { return list.isEmpty(); } }
泛型接口的使用
public class GenericDemo { public static void main(String[] args) { /* * 泛型接口的使用 */ new InterImpl<String>().show("haha"); } } interface Inter<E> { void show(E e); } //子类能明确类型,直接写类型,明确不了继续写泛型 /*class InterImpl implements Inter<String> { @Override public void show(String e) { } }*/ class InterImpl<T> implements Inter<T> { @Override public void show(T e) { //haha System.out.println(e); } }
泛型通配符
public class Person { /* * Person类 */ private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
public class Student extends Person { /* * Student类 */ public Student(String name, int age) { super(name, age); } @Override public String toString() { return "Student [name=" + getName() + ", age=" + getAge() + "]"; } }
public class Worker extends Person { public Worker(String name, int age) { super(name, age); } @Override public String toString() { return "Worker name= " + getName() + ", age=" + getAge() + "]"; } }
public class GenericDemo { public static void main(String[] args) { /* * 泛型统配符的使用 */ Set<Student> set = new HashSet<Student>(); set.add(new Student("zhansan1",21)); set.add(new Student("zhansan2",22)); set.add(new Student("zhansan3",23)); print(set); print1(set); List<Student> list = new ArrayList<Student>(); list.add(new Student("lisi1",21)); list.add(new Student("lisi2",22)); list.add(new Student("lisi3",23)); print(list); List<String> list1 = new ArrayList<String>(); list1.add("1"); list1.add("2"); list1.add("3"); print1(list1); } //可以打印set和list里面的内容 private static void print(Collection<Student> list) { for (Iterator<Student> it = list.iterator(); it.hasNext();) { Student student = (Student) it.next(); System.out.println(student); } } /* * 可以打印set和list和list1里面的内容 * 当使用泛型类或者接口时,传递的具体的类型不确定,可以通过通配符(?)来表示 */ private static void print1(Collection<?> list) { for (Iterator<?> it = list.iterator(); it.hasNext();) { //迭代出来的元素只能使用Object的方法 System.out.println(it.next()); } } }
泛型限定
public class GenericDemo { public static void main(String[] args) { /* * 泛型统配符的使用 */ Set<Student> set = new HashSet<Student>(); set.add(new Student("zhansan1",21)); set.add(new Student("zhansan2",22)); set.add(new Student("zhansan3",23)); //zhansan3 //zhansan1 //zhansan2 print(set); List<Worker> list = new ArrayList<Worker>(); list.add(new Worker("lisi1",21)); list.add(new Worker("lisi2",22)); list.add(new Worker("lisi3",23)); //lisi1 //lisi2 //lisi3 print(list); } /* * 只打印学生和工人的类型,但不能写Person * ? extends E 接收E类型或者E的子类型,上限 * ? super E 接收E类型或者E的父类型,下限 */ private static void print(Collection<? extends Person> list) { for (Iterator<? extends Person> it = list.iterator(); it.hasNext();) { Person p = it.next(); System.err.println(p.getName()); } } }
内部类
当A类中的内容要被B类直接访问,而A类还需要创建B的对象,访问B的内容时,这时,可以将B类定义到A类的内部,这样访问更为便捷,将B称为内部类(内置类,嵌套类)内部类可以直接访问外部类中的所有的成员,包含私有的,而外部类想要访问内部类中的成员,必须创建内部类的对象
public class Outer { /* * 内部类的简单介绍 */ private int num = 4; //private int num1 = 4; class Inner { void show() { System.out.println("num " + num); } //非静态内部类中不允许定义静态成员,仅允许在非静态内部类中定义静态常量static final //想要在内部类中定义静态成员,内部类也要被静态修饰 //static void show1() } void method() { //Outer.Inner inner = new Outer.Inner(); //把上面简写就是这个样子 Inner inner = new Inner(); inner.show(); } }
public class InnerClassDemo { public static void main(String[] args) { Outer outer = new Outer(); //num 4 outer.method(); } }
内部类作为成员时可以用的修饰符
public:不多见,因为更多时候内部类已经被封装到外部类中,不直接对外提供,但不随外部类的加载而加载static:
测试情况1:直接访问Outer中的Inner内部类的非静态成员
public class InnerClassDemo { public static void main(String[] args) { /* * 用public修饰内部类 * 直接访问Outer中的Inner内部类的非静态成员 * 创建内部类对象就行了,内部类作为成员,应该先有外部类对象,再有内部类对象 */ Outer.Inner in = new Outer().new Inner(); //num 4 in.show(); } }
测试情况2:对静态内部类中的非静态成员进行调用
package practice2; public class Outer { //静态方法只能访问静态变量,所以num要变成static private static int num = 4; //内部类被静态修饰后,随着Outer的加载而加载,可以把一个静态内部类理解为就是一个外部类 static class Inner { void show() { System.out.println("num " + num); } static void staticShow() { System.out.println("staticShow run"); } } }
public class InnerClassDemo { public static void main(String[] args) { Outer.Inner in = new Outer.Inner(); //num 4 in.show(); } }
测试情况3:对静态内部类中的静态成员进行调用
public class InnerClassDemo { public static void main(String[] args) { //既然静态内部类已随外部类加载,而且静态成员随着类的加载而加载,就不需要对象,直接用类名调用即可 //staticShow run Outer.Inner.staticShow(); } }
内部类访问外部类的原因
内部类能直接访问外部类的成员,是因为内部类持有了外部类的引用,外部类.this对于静态内部类不持有外部类.this,而是直接使用外部类名.
class Outer { int num = 3; class Inner { int num = 4; void show() { int num = 5; //num 5 System.out.println("num " + num); //num 4 System.out.println("num " + this.num); //num 3 System.out.println("num " + Outer.this.num); } } void method() { new Inner().show(); } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
局部内部类特点
内部类可以定义在外部类的局部位置上类名或者接口名称中有.说明是内部类,或者内部接口
class Outer { int num = 3; void method() { int x = 5; class Inner { void show() { //x 5 System.out.println("x " + x); //num 3 System.out.println("num " + num); } } //jdk1.8可以访问没有被final修饰的局部变量,jdk1.8可以 new Inner().show(); } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
内部类的继承或者实现
内部类是可以继承或者实现外部其他的类或者接口abstract class AbsDemo { abstract void show(); } class Outer { int num = 3; class Inner extends AbsDemo{ @Override void show() { //num 3 System.out.println("num " + num); } } void method() { new Inner().show(); } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
内部类对象对外提供功能的访问方式
abstract class AbsDemo { abstract void show(); } class Outer { int num = 3; public class Inner extends AbsDemo { @Override void show() { //num 3 System.out.println("num " + num); } } public Inner getObjet() { return new Inner(); } private class Inner2 extends AbsDemo { @Override void show() { //num 3 System.out.println("num " + num); } } public Inner2 getObject2() { return new Inner2(); } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); //如果Inner对外提供,可以如此获取 Outer.Inner in = out.getObjet(); in.show(); //如果Inner被private,可以通过父类型获取 AbsDemo abs = out.getObject2(); abs.show(); } }
匿名内部类
匿名内部类其实就是一个带有内容的子类对象,匿名内部类是内部类的简化形式,匿名内部类有前提,内部类必须要继承父类或者实现接口abstract class AbsDemo { abstract void show(); } class Outer { int num = 3; void method() { //不想创建具体的子类型,还想创建AbsDemo的子类对象 //可以直接使用父类型,抽象类不能new对象是因为抽象方法没有重写,直接重写就行 new AbsDemo() { @Override void show() { //num 3 System.out.println("num " + num); } }.show(); } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
如果匿名内部类有2个方法,可以写成如下形式
interface Inter { void show1(); void show2(); } class Outer { int num = 3; void method() { //内部类中方法不要过多,阅读性会很差 Inter in = new Inter() { @Override public void show1() { //show1 System.out.println("show1"); } @Override public void show2() { //show2 System.out.println("show2"); } }; in.show1(); in.show2(); } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
小练习
class Outer { int num = 3; void method() { //下面2中写法的区别 new Object() { public void show() {} }.show();//可以编译通过 /*Object obj = new Object() { public void show() {} }; obj.show();*/ //编译失败,匿名内部类是之类对象,当Object obj指向时,就被提升为Object,而Object类中没有 //定义show()方法,编译失败 } } public class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
多线程
创建线程的方法
1继承Thread类1.1定义一个类继承Thread
1.2重写run方法
1.3创建子类对象,就是创建线程对象
1.4调用start方法
package practice2; class Demo extends Thread { private String name; Demo(String name) { this.name = name; } public void run() { for (int i=0; i<10; i++) System.out.println(name + i); } } public class ThreadDemo { public static void main(String[] args) { /* * 继承Thread类实现多线程 */ Demo d1 = new Demo("张三"); Demo d2 = new Demo("李四"); //由主线程负责 d1.run(); //将d2这个线程开启 d2.start(); } }
线程对象调用run方法和调用start方法的区别
调用run方法不开启线程,仅是对象调用方法
2.实现Runnable接口
2.1定义类实现Runnable接口
2.2覆盖接口中的run方法。将线程任务代码定义到run方法中
2.3创建Thread类的对象,只有创建Thread类的对象才可以创建线程
2.4将Runnable接口的子类对象作为参数传递给Thread类的构造函数,因为线程已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样线程对象创建时就可以明确要运行的线程的任务
2.5调用Thread类的start方法开启线程
class Demo implements Runnable { public Demo() { super(); } @Override public void run() { for (int i=0; i<10; i++) { System.out.println(Thread.currentThread().getName()); } } } public class ThreadDemo2 { public static void main(String[] args) { /* * 实现Runnable接口创建多线程 */ Demo d = new Demo(); Thread d1 = new Thread(d); Thread d2 = new Thread(d); d1.start(); d2.start(); } }
源码Thread类的一个样例
class Thread { private Runnable target; Thread (Runnable target) { this.target = target; } public void run() { if (target != null) { target.run(); } } public void start() { run(); } }
第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,即是线程对象,又有线程任务。
实现Runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型,Runnable接口对线程对象和线程任务进行解耦
synchronized和volatile的区别
关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,而synchronized可以修饰方法,以及代码块。随着JDK新版本的发布,synchronized关键字在执行效率上得到很大提升,在开发中使用synchronized关键字的比率还是比较大的多线程访问volatile不会发生阻塞,而synchronized会出现阻塞
volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步。
关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。
线程安全包含原子性和可见性两个方面,Java的同步机制都是围绕这两个方面来确保线程安全的
IO
File
public class FileDemo { //提前封好一个,便于跨平台 private static final String File_SEPARATOR = System.getProperty("file.separator"); public static void main(String[] args) { /* * File类获取方法演示 */ File file = new File("e:" + File_SEPARATOR + "1.txt"); //用File类封好的文件分隔符 File file2 = new File("e:" + File.separator + "1.txt"); //获取绝对路径 String path = file.getAbsolutePath(); String fileName = file.getName(); long size = file.length(); long time = file.lastModified(); //e:\1.txt System.out.println(path); //1.txt System.out.println(fileName); //9 System.out.println(size); //1488104499833 System.out.println(time); String date = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG).format(new Date(time)); //2017年2月26日 下午06时21分39秒 System.out.println(date); } }
public class FileDemo { public static void main(String[] args) throws IOException { /* * 文件以及文件夹的创建,删除,以及存在 */ File file = new File("e:\\file.txt"); /* * 创建文件,如果文件不存在,返回true * 存在,不创建,返回false * 路径错误,IOException */ //文件创建,删除,判断 boolean b1 = file.createNewFile(); //ture System.out.println(b1); //删除完不去回收站 boolean b2 = file.delete(); //true System.out.println(b2); boolean b3 = file.exists(); //false System.out.println(b3); //目录创建,删除,判断 File dir = new File("e:\\haha\\haha\\haha"); //true boolean b4 = dir.mkdirs();//创建多级目录,不加s是创建一个目录 System.out.println(b4); //会把最有一个haha删掉,文件夹为e:\\haha\\haha //true boolean b5 = dir.delete(); System.out.println(b5); //删除目录时,如果目录中有内容,无法直接删除,只有将目录中的内容都删除,保证为空时,才能删除 //要判断是文件还是目录,必须先判断是否存在 File file1 = new File("e:\\my.txt"); //创建一个名字为my.txt的目录 file1.mkdir(); } }
public class FileDemo { public static void main(String[] args) { /* * 获取目录下的文件信息 */ //健壮性判断,必须存在,必须是目录,否则容易引发数组为null,出现NullPointerException File dir = new File("e:\\images"); String[] names = dir.list(); //当前目录下文件和文件夹名字, for (String fileName : names) { System.out.println(fileName); } //当前目录下文件和文件夹对象 File[] files = dir.listFiles(); for (File file : files) { System.out.println(file.lastModified()); } } }
文件名过滤器
public class FileMethodDemo { public static void main(String[] args) { /* * 获取目录中.txt文件 */ File dir = new File("D:\\haha"); File[] files = dir.listFiles(); //这样写太死了,程序扩展性差,要想获取其他文件,只能修改源代码 //新建文本文档 (2).txt //新建文本文档 (4).txt for (File file : files) { if (file.getName().endsWith(".txt")) System.out.println(file.getName()); } //新建文本文档 (2).txt //新建文本文档 (4).txt File[] files1 = dir.listFiles(new FileNameFileterByTxt()); for (File file : files1) { System.out.println(file.getName()); } //新建文本文档 (2).txt //新建文本文档 (4).txt File[] files2 = dir.listFiles(new FileNameFilterBySuffix(".txt")); for (File file : files1) { System.out.println(file.getName()); } } }
public class FileNameFileterByTxt implements FilenameFilter{ /* * 文件名过滤器 */ @Override public boolean accept(File dir, String name) { return name.endsWith(".txt"); } }
public class FileNameFilterBySuffix implements FilenameFilter{ /* * 文件名过滤器 */ private String suffix; public FileNameFilterBySuffix(String suffix) { super(); this.suffix = suffix; } @Override public boolean accept(File dir, String name) { return name.endsWith(suffix); } }
文件过滤器
public class FileMethodDemo { public static void main(String[] args) { /* * 获取目录中文件夹 */ File dir = new File("D:\\haha"); File[] files = dir.listFiles(new FileFilterByDir()); //D:\haha\新建文件夹 //D:\haha\新建文件夹 - 副本 for (File file : files) { System.out.println(file); } } }
public class FileFilterByDir implements FileFilter { /* * 文件过滤器 */ @Override public boolean accept(File pathname) { return pathname.isDirectory(); } }
字节输出流
OutputStream:输出字节流的超类,1操作的数据都是字节,2定义了输出字节流的基本共性功能,3输出流中定义的都是write方法,操作字节数组,操作单个字节,子类有规律,所有的子类名称后缀是父类名,前缀名是这个流对象功能public class OutputStreamDemo { public static void main(String[] args) throws IOException { /* * 字节输出流,将数据写入文件 */ File dir = new File("tempfile"); if (!dir.exists()) dir.mkdir(); File file = new File(dir,"file.txt"); //文件如果没有,会抛 FileNotFoundException //输出流目的是文件,会自动创建,如果文件存在则覆盖 FileOutputStream fos = new FileOutputStream(file); byte[] date = "this is for test".getBytes(); fos.write(date); //关闭流资源 fos.close(); } }
public class OutputStreamDemo { //window下/r/n是回车换行,linux下是/n private static final String LINE_SEPARATOR = System.getProperty("line.separator"); public static void main(String[] args) throws IOException { /* * 将数据续写到文件中,并且可以换行 */ File file = new File("tempfile\\file.txt"); //后面加参数true表示续写 FileOutputStream fos = new FileOutputStream(file, true); String str = LINE_SEPARATOR + "test"; fos.write(str.getBytes()); fos.close(); } }
public class OutputStreamDemo { public static void main(String[] args) { /* * IO异常的处理 */ File file = new File("K:\\test.txt"); FileOutputStream fos = null; try { fos = new FileOutputStream(file); fos.write("hahha".getBytes()); } catch (IOException e) { System.out.println(e.toString()); } finally { //如果fos创建失败为null,执行这一句会发生空指针异常 if (fos != null) { try { fos.close(); } catch (IOException e) { throw new RuntimeException(""); } } } } }
字节输入流
InputStream字节输入流的超类int read() 读取一个字节并返回,没有字节返回-1
int read(byte[]) 读取一定量的字节数,并存储到字节数组中,返回读取到的字节数
available可以返回文件的大小
public class FileInputStreamDemo { public static void main(String[] args) throws IOException { /* * FileInputStream读取文件演示 */ File file = new File("tempfile//file.txt"); FileInputStream fis = new FileInputStream(file); int ch = 0; //如果文件有回车,读取出来的也会回车 //abcde while ((ch = fis.read()) != -1) { System.out.print((char)ch); } System.out.println(); fis.close(); FileInputStream fis1 = new FileInputStream(file); int len = 0; byte[] buf = new byte[2]; //abcde while ((len = fis1.read(buf)) != -1) { System.out.print(new String(buf,0,len)); } } }
public class FileInputStreamDemo { public static void main(String[] args) throws IOException { /* * 复制文件 */ File srcFile = new File("tempfile//file.txt"); File targetFile = new File("tempfile//copy_file.txt"); FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(targetFile); int ch = 0; while ((ch = fis.read()) != -1) { fos.write(ch); } fis.close(); fos.close(); } }
public class FileInputStreamDemo { public static void main(String[] args) throws IOException { /* * 复制文件 */ File srcFile = new File("tempfile//file.txt"); File targetFile = new File("tempfile//copy_file_2.txt"); FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(targetFile); byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { fos.write(buf, 0, len); } fis.close(); fos.close(); } }
字符流
Reader读取字符流的抽象超类read()读取单个字符并返回,
read(char[])将数据读取到数组中,并返回读取个数
public class CharStreamDemo { public static void main(String[] args) throws IOException { /* * 字节流读取字符的问题和统计一篇文章中有多少个好字 */ writeCNText(); readCNText(); readCNTextByReader(); } private static void readCNTextByReader() throws IOException { FileReader fr = new FileReader("tempfile\\cn.txt");//这个流底层用的是FileInputStream int ch = 0; int count = 0; while ((ch = fr.read()) != -1) { if (ch == '好') count++; } //2 System.out.println(count); } private static void readCNText() throws IOException { FileInputStream fis = new FileInputStream("tempfile\\cn.txt"); //把这个大小定义为4,会读出a你和好的1个字节,因为中文一个字是2个字节 byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { String str = new String(buf,0,len); //a你好你好 System.out.println(str); } } private static void writeCNText() throws IOException { FileOutputStream fos = new FileOutputStream("tempfile\\cn.txt"); fos.write("a你好你好".getBytes()); fos.close(); } }
Writer写入字符流的抽象超类
flush()和close()的区别
flush()将流中缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用
close()关闭资源,但在关闭前会将缓冲区的数据刷新到目的地中,否则丢失数据,然后再关闭流,流不可以使用
写入数据多一定要一边写一边刷新,最后一次可以由close刷新
public class CharStreamDemo { public static void main(String[] args) throws IOException { /* * FileWriter方法演示 */ FileWriter fw = new FileWriter("tempfile\\fw.txt"); fw.write("你好谢谢再见");//这些文字都要先编码,然后写入到流的缓冲区中 fw.flush(); fw.write("又回来了"); fw.close(); } }
字符转换流
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。public class CharStreamDemo { public static void main(String[] args) throws IOException { /* * 能识别中文的码表有2个,GBK,UTF-8(3个字节存储一个汉字) * 能否将数据按照UTF-8的格式进行存储了? * 不用使用FileWriter了,因为FileWriter默认的是GBK,和操作系统有关 */ OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("tempfile\\u8cn.txt"), "utf-8"); osw.write("你好"); osw.close(); InputStreamReader isr = new InputStreamReader(new FileInputStream("tempfile\\u8cn.txt"), "utf-8"); char[] buf = new char[1024]; int len = isr.read(buf); //你好 System.out.println(new String(buf,0,len)); isr.close(); } }
OutputStreamWriter的子类是FileWriter,InputStreamReader的子类是FileReader
OutputStreamWriter和InputStreamReader是字符和字节的桥梁,也可以称之为字符转换流
字符转换流原理:字节流+编码表
FileWriter和FileReader作为子类,仅作为操作字符文件的便捷类存在
当操作的字符文件使用的是默认的编码表时可以不用父类,而直接用子类就完成操作了,简化了代码
下面这三句代码一样
用子类的条件1:操作的是文件2:使用默认编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集 InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "GBK"); FileReader fr = new FileReader("a.txt");
public class CharStreamDemo { public static void main(String[] args) throws IOException { /* * 用自定义缓冲区复制文件 */ FileReader fr = new FileReader("tempfile\\file.txt"); FileWriter fw = new FileWriter("tempfile\\copyfile.txt"); char[] buf = new char[1024]; int len = 0; while ((len = fr.read(buf)) != -1) { fw.write(buf, 0, len); } fr.close(); fw.close(); } }
public class CharStreamDemo { public static void main(String[] args) throws IOException { /* * 用BufferReader和BufferWriter复制文件 */ BufferedReader bufr = new BufferedReader(new FileReader("tempfile//file.txt")); BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile//copyfile.txt")); String line = null; while ((line = bufr.readLine()) != null) { bufw.write(line); bufw.newLine(); bufw.flush(); } bufw.close(); bufr.close(); } }
其他流
IO练习
对象序列化
序列化接口的作用:没有方法,不需要覆盖,是一个标记接口为了启动序列化功能唯一作用,给每一个需要序列化的类都分配一个序列版本号
这个版本号与该类相关联。这个版本号的作用是,在序列化时,会将这个序列号也保存到文件中,在反序列化时会读取这个序列化和本类的序列化进行匹配,如果不匹配会抛出java.io.InvalidClassException异常,是用于验证的
//标记接口,用于启动类的序列化功能 public class Person implements Serializable { //最好自己显示声明一个serialVersionUID private static final long serialVersionUID = 12345L; private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
public class ObjectStreamDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { /* * 对象的序列化和反序列化 */ writeObject(); readObject(); } //必须有这个类才能读出数据 private static void readObject() throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream("tempfile\\obj.object"); ObjectInputStream ois = new ObjectInputStream(fis); Object obj = ois.readObject(); //Person [name=zhang, age=30] System.out.println(obj.toString()); } private static void writeObject() throws IOException { Person p = new Person("zhang",30); FileOutputStream fos = new FileOutputStream("tempfile\\obj.object"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(p); } }
静态数据不会被序列化,name写成这样就不会被存进去,因为没必要类里面就有
private static String name;
对于一个非静态数据也不想序列化,需要一个关键字修饰
private transient /*瞬态*/ int age;
网络编程
4000网络通讯要素:IP地址,端口号,传输协议
public class IPDemo { public static void main(String[] args) throws UnknownHostException { /* * Ip对象 */ //获取本地主机地址对象 InetAddress ip = InetAddress.getLocalHost(); //192.168.0.103::LI-PC System.out.println(ip.getHostAddress() + "::" + ip.getHostName()); //获取其他主机的地址对象,这里写成本机的了 InetAddress ip1 = InetAddress.getByName("192.168.0.103"); //192.168.0.103::LI-PC System.out.println(ip.getHostAddress() + "::" + ip.getHostName()); } }
先运行接收端,再运行发送端
public class UDPSend { public static void main(String[] args) throws IOException { /* * 通过udp协议发送一段文本数据 * 1.需要先建立udp的socket,他具备发送或者接收功能 * 2.将数据封装到数据包中,数据包对象是DatagramPacket * 3.使用socket对象的send方法将数据包发送出去 * 4.关闭资源 */ System.out.println("udp发送端"); DatagramSocket ds = new DatagramSocket(); String text = "hello udp is coming"; byte[] buf = text.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.103"),10000); ds.send(dp); ds.close(); } }
public class UDPRece { public static void main(String[] args) throws IOException { /* * 定义一个UDP的接收端。接收发送过来的数据。并显示在屏幕上 * 1.先有udpsocket服务,并且接收端一定要明确端口,否则收不到数据 * 2.接收数据,先将数据存储到数据包中 * 3.先定义数据包 * 4.通过数据包对象获取数据包的内容,发送端的ip,发送端的端口,发送过来的数据 * 5.关闭资源 */ System.out.println("udp接收端"); DatagramSocket ds = new DatagramSocket(10000); byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); ds.receive(dp);//阻塞 String ip = dp.getAddress().getHostAddress(); int port = dp.getPort(); String text = new String(dp.getData(),0,dp.getLength()); //192.168.0.103 54035 hello udp is coming //54035是因为发送端没有明确端口 System.out.println(ip + " " + port + " " + text); ds.close(); } }
public class UDPRece2 { public static void main(String[] args) throws IOException { /* * 通过网路接收键盘录入 */ System.out.println("udp接收端"); DatagramSocket ds = new DatagramSocket(10000); while (true) { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); ds.receive(dp);//阻塞 String ip = dp.getAddress().getHostAddress(); int port = dp.getPort(); String text = new String(dp.getData(),0,dp.getLength()); //192.168.0.103 54035 hello udp is coming //54035是因为发送端没有明确端口 System.out.println(ip + " " + port + " " + text); } } }
public class UDPSend2 { public static void main(String[] args) throws IOException { /* * 键盘录入发送 */ System.out.println("udp发送端"); DatagramSocket ds = new DatagramSocket(9999); BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line = bufr.readLine()) != null) { if (line.equals("over")) break; byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.103"),10000); ds.send(dp); } ds.close(); } }
public class UDPChatTest { public static void main(String[] args) throws IOException { /* * 通过UDP实现群聊程序 * 这个程序中既有收又有发,需要同时执行,需要使用多线程技术 * 一个线程负责发,一个线程负责收 */ DatagramSocket sendSocket = new DatagramSocket(); DatagramSocket receSocket = new DatagramSocket(10002); Send send = new Send(sendSocket); Rece rece = new Rece(receSocket); Thread t1 = new Thread(send); Thread t2 = new Thread(rece); t1.start(); t2.start(); } } //发送任务 class Send implements Runnable { private DatagramSocket ds; public Send(DatagramSocket ds) { super(); this.ds = ds; } @Override public void run() { try { BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line = bufr.readLine()) != null) { byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.103"),10002); ds.send(dp); //将886也发送出去 if (line.equals("886")) break; } ds.close(); } catch (IOException e) { } } } //接收任务 class Rece implements Runnable { DatagramSocket ds; public Rece(DatagramSocket ds) { super(); this.ds = ds; } @Override public void run() { while (true) { try { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); ds.receive(dp);//阻塞 String ip = dp.getAddress().getHostAddress(); int port = dp.getPort(); String text = new String(dp.getData(),0,dp.getLength()); System.out.println(ip + " " + port + " " + text); if (text.equals("886")) System.out.println(ip + "::离开聊天室"); } catch (IOException e) { } } } }
//输入+输出 123 192.168.0.103 62775 123 23 192.168.0.103 62775 23
先启动服务器端,再启动客户端
public class TCPServer { public static void main(String[] args) throws IOException { /* *获取客户端的数据并显示在屏幕上 *1.创建服务端的socket,明确端口,监听一个端口 *2.服务端只要获取到连接过来的客户端就可以和指定的客户端通信了 *3.通过获取客户端的读取流对象读取客户端发来的数据 *4.显示在屏幕上 *5.关闭资源 */ System.out.println("服务端运行"); ServerSocket ss = new ServerSocket(10003); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); //192.168.0.103::connect System.out.println(ip + "::connect"); InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); String text = new String(buf,0,len); //hello tcp System.out.println(text); s.close(); //服务端一般不关闭,这个是为了测试 ss.close(); } }
public class TCPClient { public static void main(String[] args) throws IOException { /* * 通过TCP传输数据给服务器 * 1.建立TCP的客户端Socket,明确服务端的地址和端口 * 2.如果通道建立成功就会出现socket io流 * 客户端需要做的就是获取socket流中的输出流将数据发送目的地服务端 * 3.通过socket输出流将数据发送 * 4.关闭资源 */ System.out.println("客户端运行"); Socket s = new Socket("192.168.0.103",100 17b6c 03); OutputStream out = s.getOutputStream(); out.write("hello tcp".getBytes()); s.close(); } }
有可能有并发访问的问题,这个例子只有一个发送,一个接收,显示不出来
public class TCPClient2 { public static void main(String[] args) throws IOException { /* * 实现客户端和服务端的收发过程 */ System.out.println("客户端启动"); Socket s = new Socket("192.168.0.103",10004); OutputStream out = s.getOutputStream(); out.write("服务端,我来了".getBytes()); InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); String text = new String(buf,0,len); System.out.println(text); s.close(); } }
public class TCPServer2 { public static void main(String[] args) throws IOException { System.out.println("服务端启动"); ServerSocket ss = new ServerSocket(10004); Socket s = ss.accept(); InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); String text = new String(buf,0,len); System.out.println(text); OutputStream out = s.getOutputStream(); out.write("客户端,我已收到".getBytes()); s.close(); ss.close(); } }
网络编程练习
客户端通过键盘录入发送数据到服务端,服务端将接收到的数据显示到屏幕上的同时,将这些数据转成大写发回给客户端,客户端录入的是over时,大写转换结束public class TransServer { public static void main(String[] args) throws IOException { System.out.println("服务端启动"); //1.创建服务端socket,明确端口 ServerSocket ss = new ServerSocket(10006); while (true) { //获取客户端对象 Socket s = ss.accept(); System.out.println(s.getInetAddress().getHostAddress() + "......connected"); //2.源:socket输入流,读取客户端发过来的数据 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //3.目的:socket输出流,将转成大写的数据发送给客户端 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //4.频繁的读写操作 String line = null; while ((line = bufIn.readLine()) != null) { if ("over".equals(line)) break; System.out.println(line); //转成大写,发回给客户端 out.println(line.toUpperCase()); } //5.关闭客户端 s.close(); } } }
public class TransClient { public static void main(String[] args) throws IOException { System.out.println("客户端启动"); //1.创建socket,明确地址和端口 Socket s = new Socket("192.168.0.102",10006); //2.源,键盘录入,获取需要转换的数据 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //3.目的,网络,socket输出流 //将字符流装换为字节流,省得自己转换,如调用getbytes()方法 /* * OutputStream out = s.getOutputStream(); * OutputStreamWriter osw = new OutputStreamWriter(out); */ //外面又套一层,其实这种方法都比较低效,用PrintWriter即可 /* * OutputStream out = s.getOutputStream(); * BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(out)); */ PrintWriter out = new PrintWriter(s.getOutputStream(),true); //4.源,socket读取流,读取服务端发回来的大写数据 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //5.目的,客户端显示器,将大写数据显示出来 //6.频繁的读写操作 String line = null; while ((line = bufr.readLine()) != null) { out.println(line); if ("over".equals(line)) break; String upperText = bufIn.readLine(); System.out.println(upperText); } //7.关闭资源 s.close(); } }
上传文件
public class UploadTextServer { public static void main(String[] args) throws IOException { System.out.println("上传文本服务端启动"); //1.创建服务端socket,明确端口 ServerSocket ss = new ServerSocket(10007); while (true) { //获取客户端对象 Socket s = ss.accept(); System.out.println(s.getInetAddress().getHostAddress() + "......connected"); //2.源:socket输入流,读取客户端发过来的数据 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //3.目的:文件 PrintWriter pw = new PrintWriter(new FileWriter("tempfile\\server.txt"),true); //4.频繁的读写操作 String line = null; while ((line = bufIn.readLine()) != null) { pw.println(line); } //5.发回给客户端上传成功字样 PrintWriter out = new PrintWriter(s.getOutputStream(),true); out.println("上传成功"); //6.关闭客户端 s.close(); } } }
public class UploadTextClient { public static void main(String[] args) throws IOException { System.out.println("上传文件客户端启动"); //1.创建socket,明确地址和端口 Socket s = new Socket("192.168.0.102",10007); //2.源,读取文本文件,需要转换的数据 BufferedReader bufr = new BufferedReader(new FileReader("tempfile\\client.txt")); //3.目的,网络,socket输出流 PrintWriter out = new PrintWriter(s.getOutputStream(),true); //4.频繁的读写操作 String line = null; while ((line = bufr.readLine()) != null) { out.println(line); } //给服务端发送一个结束标记,这个标记是约定标记有点麻烦,可以更简单 //out.println("over"); //向服务端发送了结束标记,可以让服务端结束读取的动作 s.shutdownOutput(); //5.源,socket读取流,读取服务端发回来的上传成功信息 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String info = bufIn.readLine(); System.out.println(info); //6.关闭资源 bufr.close(); s.close(); } }
正则表达式
正则对字符串的常用功能操作1.匹配 2.切割 3.替换 4.获取
public class RegxDemo { public static void main(String[] args) { /* * 对QQ号进行校验 * 要求:5-15位,0不可以开头,必须都是数字 */ Scanner in = new Scanner(System.in); /* * 15613 * 15613::true * 01651 * 01651::false */ while (in.hasNext()) { String qq = in.next(); boolean bool = qq.matches("[1-9][0-9]{4,14}"); System.out.println(qq + "::" + bool); } } }
public class RegexDemo { public static void main(String[] args) { Scanner in = new Scanner(System.in); //匹配,使用String类中的matches functionDemo_1(); //切割,使用String类中的split functionDemo_2(); //替换,使用String类中的replaceAll(regex,string) functionDemo_3(); //其他三个功能内部最终使用的都是Pattern正则表达式对象 //现在需要其他功能时,字符串String类中没有对应的方法,只能找Pattern对象 functionDemo_4(); } private static void functionDemo_1() { String str = "18600001991"; //第一位是1,第二位是138其中的一个,剩下的是9个0-9的数字 String regex = "1[138]\\d{9}"; boolean flag = str.matches(regex); //true System.out.println(flag); } private static void functionDemo_2() { String str = "zhangsan,lisi,wangwu"; String regex = ","; String[] strs = str.split(regex); //zhangsan //lisi //wangwu for (String string : strs) { System.out.println(string); } str = "zhangsan lisi wangwu"; //空格加+号,一个或多个空格切 regex = " +"; strs = str.split(regex); //zhangsan //lisi //wangwu for (String string : strs) { System.out.println(string); } str = "zhangsan.lisi.wangwu"; //想用.分割必须写成\\.不然所有的字符都是切割符 regex = "\\."; strs = str.split(regex); for (String string : strs) { System.out.println(string); } //正则规则的复用,想复用,先封装。正则封装用()完成 //封装完成后由编号,从1开始。规则中被()封装的称之为组。直接通过编号就可以调用对应的组 //调用方式直接写已有的组的编号见面加上\\,如()\\1,使用已有的第一组内容。原则,先有组,才可以使用对应的编号调用 str = "ertkkkkyxgd###lfd"; regex = "(.)\\1+"; strs = str.split(regex); //ert //yxgd //lfd for (String string : strs) { System.out.println(string); } } private static void functionDemo_3() { String str = "dfdsf###dfdsf####lkg"; //不能用$符替换,因为$符有特殊含义 str = str.replaceAll("(.)\\1+", "&"); //dfdsf&dfdsf&lkg System.out.println(str); str = "dfsdl@@@klmlk###"; str = str.replaceAll("(.)\\1+", "$1"); //dfsdl@klmlk# System.out.println(str); //将电话号变成135****1111; str = "13500001111"; str = str.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); //135****1111 System.out.println(str); str = "fefldnflk489415611fdgdfd445151"; //将连续5个以上数字变成***,所以有的人发现网站屏蔽后这样写,衣二三 str = str.replaceAll("\\d{5,}", "***"); //fefldnflk***fdgdfd*** System.out.println(str); } /* * Pattern对象的使用原理 * 1.将正则表达式字符串编译成正则对象pattern * 2.通过pattern对象获取Matcher对象(匹配器对象) * 3.通过匹配器对象对字符串进行规则的匹配,结果都在匹配器中 * 4.通过匹配器对象的功能获取结果 * 范例代码: * Pattern p = Pattern.compile("a*b"); * Matcher m = p.matcher("aaaaab"); * boolean b = m.matches(); */ private static void functionDemo_4() { String str = "da jia zhu yi la,ming tian fang jia le!"; String regex = "[a-zA-Z]{3}";//取出由3个字母组成的单词 Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); //jia //zhu //min //tia //fan //jia while (m.find()) { System.out.println(m.group()); } regex = "\\b[a-zA-Z]{3}\\b"; p = Pattern.compile(regex); m = p.matcher(str); //3::jia::6 //jia //7::zhu::10 //zhu //32::jia::35 //jia while (m.find()) { System.out.println(m.start() + "::" + m.group() + "::" + m.end()); System.out.println(str.substring(m.start(), m.end())); } } }
正则表达式练习
public class RegexDemo2 { public static void main(String[] args) { test1(); test2(); test3(); } private static void test1() { /* * 我我我....我要学学....软...软件....件 * 变成我要学软件 */ String str = "我我我....我要学学....软...软件....件"; //一个或者多个点替换成空字符串 str = str.replaceAll("\\.+", ""); //我我我我要学学软软件件 System.out.println(str); str = str.replaceAll("(.)\\1+", "$1"); //我要学软件 System.out.println(str); } private static void test2() { /* * 23.12.10.5 192.168.100.223 3.3.3.3 10.10.10.10 * 将ip按照顺序排序 * 将ip切割再按照字典序排序是错误的,因为比较的位数不一样,应该都补足3位再进行比较 * 如何补0?每一段的位数不同,补零的个数也不同,按所需的最多的零补,每一段都补2个零 * 有的地址段多了,取每一段的最后三位 */ String ipStr = "23.12.10.5 192.168.100.223 3.3.3.3 10.10.10.10"; ipStr = ipStr.replaceAll("(\\d+)", "00$1"); //0023.0012.0010.005 00192.00168.00100.00223 003.003.003.003 0010.0010.0010.0010 System.out.println(ipStr); ipStr = ipStr.replaceAll("0*(\\d{3})", "$1"); //023.012.010.005 192.168.100.223 003.003.003.003 010.010.010.010 System.out.println(ipStr); String[] ips = ipStr.split(" +"); Arrays.sort(ips); //3.3.3.3 //10.10.10.10 //23.12.10.5 //192.168.100.223 for (String ip : ips) { //去除前导零并且输出 System.out.println(ip.replaceAll("0*(\\d+)", "$1")); } } private static void test3() { /* * 对邮件地址进行校验 */ String mail = "itcast2013@itcast.cn"; //数字字母一次或者多次+@符号+字母或者数字+.+字母2次到3次 String regex = "[a-zA-Z_0-9]+@[a-zA-Z0-9]+\\.+[a-zA-Z]{2,3}"; boolean b = mail.matches(regex); //itcast2013@itcast.cn::true System.out.println(mail + "::" + b); //有可能有多个后缀 mail = "itcast2013@itcast.com.cn"; //限制后缀为1次到3次 regex = "[a-zA-Z_0-9]+@[a-zA-Z0-9]+(\\.+[a-zA-Z]{2,3}){1,3}"; b = mail.matches(regex); //itcast2013@itcast.com.cn::true System.out.println(mail + "::" + b); //比较笼统的方式 regex = "\\w+@\\w+(\\.\\w+)+"; } }
public class NetSpider { public static void main(String[] args) throws IOException { /* * 网络爬虫,其实就是一个应用程序,获取网络中的指定信息(符合指定规则的信息) * 网络中的邮件地址 */ File file = new File("tempfile\\mail.html"); String regex = "\\w+@\\w+(\\.\\w+)+"; List<String> list = getMail(file,regex); //list 515123@163.com //list 28651321@qq.com for (String mail : list) { System.out.println("list " + mail); } String urlStr = "http://bbs.tianya.cn/post-444-48585-1.shtml"; list = getMailsByNet(urlStr, regex); //url 2112176384@qq.com //url 1337976723@qq.com //url 2640326225@qq.com for (String mail : list) { System.out.println("url " + mail); } } //基于网络的爬虫 public static List<String> getMailsByNet(String urlStr,String regex) throws IOException { List<String> list = new ArrayList<>(); //1.将urlStr封装成url对象 URL url = new URL(urlStr); //2.打开链接 URLConnection conn = url.openConnection(); //3.获取读取流 InputStream in = conn.getInputStream(); BufferedReader bufr = new BufferedReader(new InputStreamReader(in)); //4.将正则表达式编译成对象 Pattern p = Pattern.compile(regex); String line = null; while ((line = bufr.readLine()) != null) { Matcher m = p.matcher(line); while (m.find()) { list.add(m.group()); } } bufr.close(); return list; } //基于本地的爬虫 private static List<String> getMail(File file, String regex) throws IOException { List<String> list = new ArrayList<>(); //1.读取文件 BufferedReader bufr = new BufferedReader(new FileReader(file)); //2.将正则规则编译成对象 Pattern p = Pattern.compile(regex); String line = null; while ((line = bufr.readLine()) != null) { Matcher m = p.matcher(line); while (m.find()) { list.add(m.group()); } } bufr.close(); return list; } }
反射
反射技术:动态的获取指定的类以及动态的调用类中的内容应用程序已经写好,后期出现的接口子类无法在该应用程序中用new创建对象该怎么办?既然子类不确定,可以通过对外提供配置文件的形式,将不确定的信息存储到配置文件中即可,该程序只要之前写好如何读取配置文件信息即可。把具体实现的子类的名称定义到配置文件中。如果存储了指定的子类名,就根据具体的名称找该类并进行加载和对象的创建,这些动作都在前期定义软件时写好的。没有类之前就将创建对象的动作完成了。这就是动态获取指定的类,并使用类中的功能,这就是反射技术。反射技术的出现大大提高了程序的扩展性
public class Person { private String name; private int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { /* * 要想获取字节码文件中的成员,必须先获取字节码文件对象 * 获取字节码文件对象的方式 * 1.通过Object类的getClass方法 * 虽然通用,但是前提必须有指定类,并对该类进行对象的创建,才可以调用getClass()方法 * 2.使用任意数据类的一个静态成员class,所有的数据类型都具备的一个属性 * 好处,不用new对象,但是,还需要使用具体的类 * 3.使用Class类中的forName方法,通过给定类名来获取对应的字节码文件对象 * 只要知道类的名字就可以,获取对应的字节码文件直接由forName方法自动完成 * 这就是反射技术获取字节码文件的方式 */ getClass_1(); getClass_2(); getClass_3(); } private static void getClass_1() { Person p1 = new Person(); Person p2 = new Person(); Class c1 = p1.getClass(); Class c2 = p2.getClass(); //true System.out.println(c1 == c2); //practice8.Person System.out.println(c1.getName()); } private static void getClass_2() { Class clazz = Person.class; } private static void getClass_3() throws ClassNotFoundException, InstantiationException, IllegalAccessException { //必须加上包名 String className = "practice8.Person"; Class clazz = Class.forName(className); System.out.println(clazz); /* * 通过newInstance()就可以创建字节码对象所表示的类的实例 * 通常被反射的类都会有提供空参数的构造函数 * 没有对应的构造函数,会报InstantiationException * 如果有提供,但是权限不够,会报IllegalAccessException(就是把Person类构造函数前面的public去掉) */ Object obj = clazz.newInstance(); /* * 和上面是一个效果 * Person person = new Person(); * 1.加载Person类,并将Person类封装成字节码文件对象 * 2.通过new创建Person对象 * 3.调用构造函数对对象初始化 */ //practice8.Person@139a55 对象类型和哈希值 System.out.println(obj); } }
public class ReflectDemo2 { public static void main(String[] args) throws Exception { /* * 通过指定的构造函数初始化对象 * 1.获取字节码文件对象 * 2.再获取给定的构造函数 * 3.通过构造函数初始化对象 */ getConstructorDemo(); } private static void getConstructorDemo() throws Exception { String className = "practice8.Person"; Class clazz = Class.forName(className); //获取指定的构造器,获取Person类中2个参数string,int的构造函数 Constructor cons = clazz.getConstructor(String.class,int.class); //有了构造器对象后,通过构造器对象来初始化类对象 Object obj = cons.newInstance("wangwu",23); //Person [name=wangwu, age=23] System.out.println(obj); } }
public class ReflectDemo3 { public static void main(String[] args) throws Exception { //获取字段 getFieldDemo(); //获取方法 getMethodDemo(); //获取静态方法 getMethodDemo2(); } private static void getFieldDemo() throws Exception { String className = "practice8.Person"; Class clazz = Class.forName(className); String fieldName = "age"; //获取的是公共字段 //Field field = clazz.getField(fieldName); Field field = clazz.getDeclaredField(fieldName); //private int practice8.Person.age System.out.println(field); //getXXX获取类中公共成员 //getDeclaredXXX获取本类中已有的成员 Object obj = clazz.newInstance(); field.setAccessible(true);//取消权限检查,暴力访问,一般不访问私有 field.set(obj, 30);//IllegalAccessException:age字段是私有的 //30 System.out.println(field.get(obj)); } private static void getMethodDemo() throws Exception { String className = "practice8.Person"; Class clazz = Class.forName(className); String methodName = "show"; Method method = clazz.getMethod(methodName, String.class, int.class); Object obj = clazz.newInstance(); //调用Person的函数会输出 show run.... name wangwu age 20 method.invoke(obj, "wangwu",20); } private static void getMethodDemo2() throws Exception { String className = "practice8.Person"; Class clazz = Class.forName(className); String methodName = "staticShow"; Method method = clazz.getMethod(methodName, null); //调用Person的函数会输出 static show run.... method.invoke(null, null); } }
反射练习
public class NoteBook { /* * 笔记本类 */ //运行 public void run() { System.out.println("notebook run"); } //使用USB的设备,多态的体现 public void useUSB(USB usb) { if (usb != null) { usb.open(); usb.close(); } } }
public interface USB { /* * 为笔记本类设计的USB接口 */ void open(); void close(); }
public class MouseByUSB implements USB { /* * 实现USB接口的鼠标 */ @Override public void open() { System.out.println("mouse open"); } @Override public void close() { System.out.println("mouse close"); } }
public class KeyByUSB implements USB { /* * 实现USB接口的键盘 */ @Override public void open() { System.out.println("key open"); } @Override public void close() { System.out.println("key close"); } }
usb.properties(tomcat是用XML文件进行配置)
usb1=practice9.MouseByUSB usb2=practice9.KeyByUSB
public class NoteBookMain { public static void main(String[] args) throws Exception { /* * 案例1: * 阶段1:笔记本电脑运行 NoteBook run() * 阶段2:想要使用一些外围设备,比如鼠标,键盘 * 为了提高笔记本的扩展性,应该降低这些设备和笔记本的耦合性,需要接口 * 只需要在设计之初定义一个接口,而且笔记本在使用这个接口 * 后期有了USB设备后,需要不断new对象才可以用,每一次都要修改代码 * 能不能不修改代码就使用后期的设备 * 设备不明确,而前期还要对其进行对象的建立,需要反射技术 * 对外提供一个配置文件 */ NoteBook book = new NoteBook(); //函数运行输出 notebook run book.run(); //book.useUSB(null); //函数输出mouse open //mouse close //book.useUSB(new MouseByUSB()); //通过反射的方法重新设计应用程序,以提高更好的扩展性 File configFile = new File("tempfile\\usb.properties"); if (!configFile.exists()) configFile.createNewFile(); FileReader fr = new FileReader(configFile); //为了获取其中的键值信息方便,建立properties Properties prop = new Properties(); prop.load(fr); for (int i=1; i<=prop.size(); i++) { String className = prop.getProperty("usb" + i); Class clazz = Class.forName(className); USB usb = (USB)clazz.newInstance(); //函数输出 //mouse open //mouse close //key open //key close book.useUSB(usb); } fr.close(); } }
相关文章推荐
- JAVA与模式 学习笔记(一) 统一的建模语言UML介绍(1)
- JAVA与模式 学习笔记(一) 统一的建模语言UML介绍(2)
- 我的Thinking in Java学习笔记(六)(zt)
- java对象序列化学习笔记(z)
- JAVAGUIDE(学习笔记1)
- 我的Thinking in Java学习笔记(九)
- JAVA学习笔记之Collection
- Java中文处理学习笔记——Hello Unicode
- Thinking in Java学习笔记(三)(zt)
- Java中文处理学习笔记
- java对象序列化学习笔记
- 我的Thinking in Java学习笔记(2)
- 我的Thinking in Java学习笔记(1)
- 我的Thinking in Java学习笔记(四) (zt)
- Java 学习笔记
- JAVA与模式 学习笔记(一) 统一的建模语言UML介绍(2)
- JAVA学习笔记之JIRA
- 我的Thinking in Java学习笔记(四)
- 我的Thinking in Java学习笔记(七)
- Thinking in Java学习笔记(2)(zt)