您的位置:首页 > 编程语言 > Java开发

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();
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: