javase笔记 15-21 ( 写太多 懒得排版了)



48 List的子类
Collection
|-List
|-ArrayList: 数组数据结构 特点:查询速度快,增删稍慢
|-LinkedList:  链表数据结构 特点:增删速度很快,查询稍慢
|-Vector: 底层是数组数据结构  线程同步 被ArrayList 取代








49 vector
枚举就是Vector特有的去除方式
发现枚举和迭代期很像
其实枚举和迭代是一样的
因为枚举的名字以及方法的名称都过长,所以被迭代器取代了.
所以取元素还是推荐迭代器,为什么讲枚举?因为IO中有个用枚举的.


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
Vector v = new Vector();
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");

Enumeration en = v.elements();
while(en.hasMoreElements())
{
System.out.println(en.nextElement());
}
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}






50 linkedList 特有方法


当元素为空时 获取和删除元素返回NULL
添加元素
offerFirst();
offerLast();
获取元素
peekFirst();
PeekLast();
删除元素
poolFirst
poolLast()




package pack;   
import java.util.*;


class Demo
{
public static void main(String[] args)  
{
LinkedList link = new LinkedList();
link.offerFirst("java01");
link.offerFirst("java02");
link.offerFirst("java03");
link.offerFirst("java04");

sop(link);


link.offerLast("java01");
link.offerLast("java02");
link.offerLast("java03");
link.offerLast("java04");
sop(link);

sop(link.peekFirst());
sop(link.peekLast());

sop("remove:"+link.pollFirst());
sop(link);

while(!link.isEmpty())
{
sop(link.pollFirst());
}

sop(link); //清空了
sop(link.pollFirst()); //null
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}




51 ArrayList LinkList 的选择
只要元素不是特别多 就用ArrayList,增删时间是可以允许的
大量的增删其实并不多见,这种情况下采用LinkList




52  HashSet
Collection --
|-Set 元素是无序的(存入和去除的顺序不一定一致),元素不可以重复
|-HashSet 底层数据结构是哈希表
|-TreeSet 


HashSet
哈希表: 先看哈希值(通过hashCode()方法),如果哈希值一样再判断是否是同一个对象(equals()方法)
Object 中默认的 hashCode() 反回的是地方 .  equals() 默认判断是否是同一个引用




package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
HashSet hs = new HashSet();
hs.add("java01");
hs.add("java02");
hs.add("java03");
hs.add("java04");
hs.add("java03");
hs.add("java04");

//插入重复的,存入的只有4个

//取值只有迭代器一种方法
Iterator it = hs.iterator();
while(it.hasNext())
{
sop(it.next());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素


遇到的问题是 姓名年龄相同的人,可以是不同的对象,导致hashCode()不同,所以被存入.
哈希值(通过hashCode()方法)不同,直接存入
哈希值相等,通过equals()方法判断不是同一个对象,再存入.


因此阻止一个对象被存入的方式是:
step 1 使其hashCode与其他的有相同,另外最好做到内容不同的hashCode也不同,以免调用equals
step 2 通过equals比较发现,与其他元素相同




package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
Person p1 = new Person("lilei",13);
Person p2 = new Person("lii",14);
Person p3 = new Person("lucy",12);
Person p4 = new Person("lilei",13);

HashSet hs = new HashSet();
hs.add(p1);
hs.add(p2);
hs.add(p3);
hs.add(p4);

Iterator it = hs.iterator();
while(it.hasNext())
{

Object obj = it.next();
if(!(obj instanceof Person))
return;
Person p = (Person)obj;
sop(p.getName() + " " + p.getAge());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}






class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}

String getName()
{
return name;
}

int getAge()
{
return age;
}

//内容相同的String对象 hashCode相同
public int hashCode()
{
return name.hashCode()+age; 
}

//再让其equals
public boolean equals(Object obj) //注意这里是Object
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return name.equals(p.name) && age==p.age;
}
}


对于判断元素是否存在 以及删除等操作,依赖的方法先依赖hashCode 再 依赖 equals




53 TreeSet
可以对Set集合中的元素进行排序
底层数据结构是二叉树
保证元素唯一性的一句 compareTo 方法return 0 (重复不能进来)


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
TreeSet ts = new TreeSet();
ts.add("cba");
ts.add("abcd");
ts.add("aaa");
ts.add("bca");

Iterator it = ts.iterator();
while(it.hasNext())
{
sop(it.next());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


F:\>java pack.Demo
aaa
abcd
bca
cba




54 TreeSet 对自定义进行排序
方式一:
需要让自定义类实现Comparable接口,实现public int compareTo(Object obj).




package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
TreeSet ts = new TreeSet();
ts.add(new Person("lisi02",22));
ts.add(new Person("lisi007",20));
ts.add(new Person("lisi009",19));
ts.add(new Person("lisi01",40));
ts.add(new Person("lisi01",40)); //compareTo() 相同的 因为是Set子类所以不能插进去



Iterator it = ts.iterator();
while(it.hasNext())
{
Person p = (Person)(it.next());
sop(p.getName()+" "+p.getAge());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}




class Person implements  Comparable //该接口强制让学生具备比较性
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}

String getName()
{
return name;
}

int getAge()
{
return age;
}


public int compareTo(Object obj)
{
if(!(obj instanceof Person))
{
throw new RuntimeException("不是学生对象");
}

Person p = (Person)obj;
int ret = name.compareTo(p.name);
if( ret == 0)
{
return age-p.age;
}
else
{
return  ret;
}

}

}


方法二: 
当元素不具备比较性或者具备的比较性不是所需要的(别人写的类),
这时需要让集合自身有比较性
定义比较器(实现Comparator 覆盖compare方法) 将比较器对象作为参数传递给TreeSet集合的构造函数


当两种比较方法都有时,以比较器为准.




package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
TreeSet ts = new TreeSet(new myComp());

ts.add(new Person("lisi02",22));
ts.add(new Person("lisi007",20));
ts.add(new Person("lisi009",19));
ts.add(new Person("lisi01",40));
ts.add(new Person("lisi01",40)); //compareTo() 相同的 因为是Set子类所以不能插进去



Iterator it = ts.iterator();
while(it.hasNext())
{
Person p = (Person)(it.next());
sop(p.getName()+" "+p.getAge());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


class myComp implements Comparator
{
public int compare(Object o1,Object o2)
{
if(!((o1 instanceof Person)&&(o2 instanceof Person)))
{
throw new RuntimeException("参数错误");
}
Person p1 = (Person)o1;
Person p2 = (Person)o2;

int ret = p1.getName().compareTo(p2.getName());
if( ret == 0)
{
return p1.getAge()-p2.getAge();
}
else
{
return ret;
}
}
}




class Person 
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}

String getName()
{
return name;
}

int getAge()
{
return age;
}
}


55 泛型
泛型格式:通过<>来定义要操作的引用类型
通常在集合框架内很常见


两个好处:
1 在一个集合中加入多种数据类型时,可以在编译时显示出来
2 在迭代器使用泛型,可以避免类型转化


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
ArrayList<String> al = new ArrayList<String>();  //使用泛型确定集合数据类型 
al.add("abc01");
al.add("abc092");
al.add("abc0311");

Iterator<String> it = al.iterator(); //使用泛型确定迭代器取出的数据类型
while(it.hasNext())
{
sop(it.next().length()); //直接调用String类的函数 .length()
}
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}




自定义类型时


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
TreeSet<Person> ts = new TreeSet<Person>(new myComp());

ts.add(new Person("lisi02",22));
ts.add(new Person("lisi007",20));
ts.add(new Person("lisi009",19));
ts.add(new Person("lisi01",40));
ts.add(new Person("lisi01",40)); //compareTo() 相同的 因为是Set子类所以不能插进去



Iterator<Person> it = ts.iterator();
while(it.hasNext())
{
Person p = it.next();
sop(p.getName()+" "+p.getAge());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


class myComp implements Comparator<Person> //泛型  <E>
{
public int compare(Person p1,Person p2)  //  这里直接可以Person了 ,public int compare(E,E)
{
 
int ret = p1.getName().compareTo(p2.getName());
if( ret == 0)
{
return p1.getAge()-p2.getAge();
}
else
{
return ret;
}
}
}




class Person 
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}

String getName()
{
return name;
}

int getAge()
{
return age;
}
}






56 泛型类


什么时候定义泛型类
当类中要操作的引用数据类型不确定的时候,早期定义
Object来完成扩展,现在定义泛型来完成扩展.  (注意不能定义基本数据类型)


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
Utils<Person> t = new Utils<Person>(); //不能定义int等基本数据类型,会报错
t.setObject(new Person("zhangsan",24));
sop(t.getObject().getName());
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


 
//泛型类
class Utils<T>
{
private T t;
public void setObject(T t)
{
this.t  = t;
}

public T getObject()
{
return t;
}


}


class Person 
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}

String getName()
{
return name;
}

int getAge()
{
return age;
}
}




53 泛型方法
泛型类定义的泛型,在整个类中有效,如果被方法使用,
那么泛型对象明确操作的具体类型后,所有要操作的类型就固定了


为了让不同方法可以操作不同类型,而且类型还不确定,
可以把泛型定义在方法上,将泛型放在返回值类型前面


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
Utils<Integer> t = new Utils<Integer>();
t.show("abc");
t.show(new Integer(4));
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


 
 
class Utils<T>
{
public <Q> void show(Q t) //泛型方法  这个Q只作用于这个方法作用范围内
{
Demo.sop("show "+t);
}
}




54 泛型静态方法
静态方法不可以访问类上定义的泛型,
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
Utils.show("hahha");
 
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


 
class Utils<T>
{
// 静态方法中 泛型要定义在方法上,不能访问泛型类的泛型
public static <Q> void show(Q t)  //<Q>放在返回值前面 别放错位置
{
Demo.sop("show "+t);
}
}


55 泛型接口


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
InterImpl i1 = new InterImpl();
i1.show("abc");
 
InterImpl2<String> i2 = new InterImpl2<String>();
i2.show("bcd");
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}




interface Inter<T>
{
public abstract void show(T t);
}


class InterImpl implements Inter<String>
{
public void show(String s)
{
Demo.sop(s);
}
}


class InterImpl2<T> implements Inter<T>
{
public void show(T t)
{
Demo.sop(t);
}
}


56 泛型限定
1 <?>的使用
? 通配符,也可以理解为占位符




package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc");
al.add("bac");
al.add("cba");

ArrayList<Integer> al1 = new ArrayList<Integer>();
al1.add(1);
al1.add(2);
al1.add(3);

printColl(al);
printColl(al1);


 
}

public static void sop(Object obj)
{
System.out.println(obj);
}


public static void printColl(ArrayList<?> al)
{
Iterator<?> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}


2 <? extends E>  E 及其子类 上限定
  <? super E>   E 及其父类  下限定
 
package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("zhangsan"));
al.add(new Person("lisi"));
al.add(new Person("wangmazi"));




ArrayList<Student> al1 = new ArrayList<Student>();
al1.add(new Student("zhangsan2",100));
al1.add(new Student("lisi2",150));
al1.add(new Student("wangmazi2",130));


printColl(al);
sop("-----");
printColl(al1);
}

public static void sop(Object obj)
{
System.out.println(obj);
}


public static void printColl(ArrayList<? extends Person> al)  //限定可以传入Person及其子类
{
Iterator<? extends Person> it = al.iterator();
while(it.hasNext())
{
it.next().getName();
}
}
}




class Person 
{
private String name;
Person(String name)
{
this.name = name;
}


public void getName()
{
Demo.sop(name);
}
}


class Student extends Person
{
private int score;
Student(String name,int score)
{
super(name);
}

public void getScore()
{
Demo.sop(score);
}
}




 57 Map 集合: 
 
 该集合存储键值对,一对对往里面存,且要保持唯一性
 添加
 V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。 
 void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。 
 
 删除 
  V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 
 void clear() 
          从此映射中移除所有映射关系(可选操作)。 
 
 判断
  boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 true。 
 boolean containsValue(Object value) 
          如果此映射将一个或多个键映射到指定值,则返回 true。 


 
 获取
  V get(Object key) 
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null 
 int size() 
          返回此映射中的键-值映射关系数。 
   
 //所有的键
 Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。 
//所有的值
Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。


 Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。
 
 
map集合接口的子类
Map--
|--Hashtable 底层是哈希表数据结构,不可以存入null做为键或者值 ,线程同步
|--HashMap  底层是哈希表数据结构,允许存入null做为键或者值 ,线程不同步
|--TreeMap 底层是二叉树数据结构,线程不同步,可以给map中的键排序.
其实set底层用的是map
和哈希表有关的都要支持public int hashCode() 和 public boolean equals(Object)方法
和树有关的要实现comparable接口或者传入Comparator接口的子类


map 集合的两种取出方式:
1 Set<> keySet() : 将map中所存的键存到set集合,而set有迭代期
可以通过迭代方法取出所有的键,根据get方法得到值


2 Set<Map.Entry<k,v>> entrySet():
将map集合中的映射关系取出来,而这个关系是<Map.Entry<k,v> ,存入到Set中




package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
//添加元素
Map<String,String> map = new HashMap<String,String>();
sop("put:"+map.put("01","zhangsan1")); //返回null
map.put("02","zhangsan2");
map.put("03","zhangsan3");


map.put(null,"haha");  //null是可以存入HashMap中的
Map<String,String> map2 = new HashMap<String,String>();
map2.putAll(map); //将map中的所有值添加到map2中

//添加重复的key的情况
/*
V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。 
某个键第一次被put 会返回null
第二次put,会覆盖原来的值,并返回被覆盖的值
*/
sop("put覆盖:"+map2.put("01","wangwu"));//put覆盖:zhangsan1

sop(map2);
//{null=haha, 01=wangwu, 02=zhangsan2, 03=zhangsan3}

//判断
sop("contains key:"+map2.containsKey("02") + " "+ map2.containsKey("0r"));
sop("contains value:"+map2.containsValue("zhangsan1")+" "+map2.containsValue("lisi"));

//获取
sop("size:"+map2.size()); //4
sop("get:"+map2.get("01")); //zhangsan1
sop("get:"+map2.get("04")); //null
//获取所有的值
Collection<String> co = map2.values();
sop("values:"+co); //values:[haha, zhangsan1, zhangsan2, zhangsan3]


// map集合的两种取出方法

// 方法1 keySet() 法
sop("方法1:");
//获取所有的键的set集合 keySet()
Set<String> keyset = map2.keySet();
//通过迭代器获取键,通过键
Iterator<String> it = keyset.iterator();
while(it.hasNext())
{
String key = it.next();
sop(key + " " + map2.get(key) );
}


//方法2:
sop("方法2:");
Set<Map.Entry<String,String>> keyset2 = map2.entrySet();
Iterator<Map.Entry<String,String>> it2 = keyset2.iterator();
while(it2.hasNext())
{
Map.Entry<String,String> me = it2.next();
sop(me.getKey()+" "+me.getValue());
}
}

public static void sop(Object obj)
{
System.out.println(obj);
}


 
}


58 TreeMap 
可以用来给键排序,但需要实现comparable接口或者传入Comparator接口的子类


59 总结下
常用的集合有
1Collection: 
单值可重复:
ArrayList:一般常用
LinkList:增删频繁时用
单值不可重复:
HashSet:哈希表
TreeSet:树,自动排序


2Map:
HashMap:哈希表
TreeMap:树,自动排序




60 Collections 工具类
java专门给集合操作的工具类,


1)对List进行排序


static <T extends Comparable<? super T>>  void  sort(List<T> list) 
          根据元素的自然顺序 对指定列表按升序进行排序。 
即限定T是Comparable的子类,即T具有比较性.
Comparable<? super T> 的意思是可以接收T的子类
或者:
static <T> void  sort(List<T> list, Comparator<? super T> c) 
          根据指定比较器产生的顺序对指定列表进行排序。
 


2) 求集合最大值
static <T extends Object & Comparable<? super T>>  T max(Collection<? extends T> coll) 
          根据元素的自然顺序,返回给定 collection 的最大元素。 
static <T> T  max(Collection<? extends T> coll, Comparator<? super T> comp) 
          根据指定比较器产生的顺序,返回给定 collection 的最大元素。 


3) 二分法搜索
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
 
public static <T> int binarySearch(List<? extends T> list,T key, Comparator<? super T> c)


搜索之前必须按相应的方式排序
当且仅当此键被找到时,返回的值将 >= 0


4) 将集合中的元素全部替换
public static <T> void fill(List<? super T> list, T obj)
使用指定元素替换指定列表中的所有元素。


5) relaceAll reverse
public static <T> boolean replaceAll(List<T> list,
                                     T oldVal,
                                     T newVal)
public static void reverse(List<?> list)


6) 逆向比较器
static <T> Comparator<T> reverseOrder() 
          返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。 
static <T> Comparator<T>  reverseOrder(Comparator<T> cmp) 
          返回一个比较器,它强行逆转指定比较器的顺序。 



7) 获得线程同步的集合
static <T> Collection<T> 
 synchronizedCollection(Collection<T> c) 
          返回指定 collection 支持的同步(线程安全的)collection。 
static <T> List<T> 
 synchronizedList(List<T> list) 
          返回指定列表支持的同步(线程安全的)列表。 
static <K,V> Map<K,V> 
 synchronizedMap(Map<K,V> m) 
          返回由指定映射支持的同步(线程安全的)映射。 
static <T> Set<T> 
 synchronizedSet(Set<T> s) 
          返回指定 set 支持的同步(线程安全的)set。 
static <K,V> SortedMap<K,V> 
 synchronizedSortedMap(SortedMap<K,V> m) 
          返回指定有序映射支持的同步(线程安全的)有序映射。 
static <T> SortedSet<T> 
 synchronizedSortedSet(SortedSet<T> s) 
          返回指定有序 set 支持的同步(线程安全的)有序 set。 


8)List 中交换两个元素
static void swap(List<?> list, int i, int j) 
          在指定列表的指定位置处交换元素。 
 
9) shuffle 
static void shuffle(List<?> list) 
          使用默认随机源对指定列表进行置换。 
static void shuffle(List<?> list, Random rnd) 
          使用指定的随机源对指定列表进行置换。 
 
   
package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{

List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("adcdefgjds");
list.add("zz");
list.add("1qswd");
list.add("zz");

//List排序
sop(list);
Collections.sort(list); 
sop(list);
Collections.sort(list,new StrLenComparator());//使用自定义比较器进行排序
sop(list);

//Collection最大值
sop(Collections.max(list)); //zz 自然顺序
sop(Collections.max(list,new StrLenComparator()));//adcdefgjds 自定义比较器顺序

sop("index "+Collections.binarySearch(list,"abcd")); //2

//replaceAll 
Collections.replaceAll(list,"zz","zzz");
sop(list);

//reverse
Collections.reverse(list);
sop(list);

//fill 替换元素
Collections.fill(list,"aaa");
sop(list); //[aaa, aaa, aaa, aaa, aaa]

// 逆向比较器
TreeSet<String> set = new TreeSet<String>(Collections.reverseOrder()); //返回一个逆自然顺序的比较器
set.add("hello");
set.add("aab");
set.add("az");
set.add("zio1");
sop(set); //[zio1, hello, az, aab]

TreeSet<String> set1 = new TreeSet<String>(Collections.reverseOrder(new StrLenComparator()));
//返回一个与指定比较器相反的比较器
set1.add("hello23");
set1.add("aab");
set1.add("az");
set1.add("zio1");
sop(set1);  

//交换List中的两个元素
List<String> list2 = new ArrayList<String>();
list2.add("abcd");
list2.add("adcdefgjds");
list2.add("zz");
list2.add("1qswd");
list2.add("zz");
sop(list2);
Collections.swap(list2,1,2);
sop(list2);

//随机排列
Collections.shuffle(list2);
sop(list2);




}

public static void sop(Object obj)
{
System.out.println(obj);
}


 

}


//根据字符串长度进行排序
class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
return s1.length()-s2.length();
}
}


 61 Arrays 操作数组的工具类
 static <T> List<T>  asList(T... a) 
          返回一个受指定数组支持的固定大小的列表 


 binarySearch 二分法查找
 sort 排序
 equals  如果两个数组以相同顺序包含相同的元素,则两个数组是相等的
 copyOf 复制指定长度的数组
 fill 填充数组
 toString化为String类型
 
 package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{

int[] arr = {5,4,3,7,8,0};
Arrays.sort(arr); //按自然顺序排序
sop( Arrays.toString(arr) ); //转为String类型
sop( Arrays.binarySearch(arr,5) ); //排序后才能用二分查找法 查找元素的索引

/*把数组变成List集合
static <T> List<T>   asList(T... a) 
        返回一个受指定数组支持的"固定大小"的列表。 
好处是:可以使用集合中的函数 比如.contains()  .get() .indexOf()
注意: 1将数组变成集合不可以使用增删功能,如果增删,会发生异常
2 返回值是List,不能写ArrayList或者LinkList等子类
3 如果数组中的元素是对象,那么变成集合时,数组中元素直接变集合元素
如果数组中的元素是基本数据类型,那么数组直接变集合元素
*/
//基本数据类型的情况
List<int[]> al = Arrays.asList(arr);
sop(al); //[[I@18b3364] 这样觉得没什么用

//使用自动装箱为引用类型 就可以元素变集合元素了
Integer[] arr3 = {1,2,3,4};
List<Integer> al3 = Arrays.asList(arr3);
sop(al3); //[1, 2, 3, 4]

//引用类型的情况
String[] arr2 = {"abc","def","kkk","123"};
List<String> al2 = Arrays.asList(arr2);
sop(al2);// [abc, def, kkk, 123]
sop( al2.contains("abc") ); //true
sop( al2.indexOf("def") ); //1
sop( al2.get(0) );//abc
}

public static void sop(Object obj)
{
System.out.println(obj);
}
 
}


62 集合转数组
为什么要将集合转数组?
为了限定对元素的操作,不需要增删操作


函数:
Collection接口下:
public <T> T[] toArray(T[] a)
示例:
package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc");
al.add("chs");
al.add("hahaha");

//当指定类型的长度小于集合的size,则会新建一个和size一样大小的数组
//当指定类型的长度大于集合的size,会使用这个数组,并且填充null
//所以创建一个大小和集合size一样的数组最优
String[] arr = al.toArray(new String[al.size()]);  
sop(Arrays.toString(arr));
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


 
 class Person
 {
Person()
{
Demo.sop("person");
}
 }


63 高级for循环
格式
for(数据类型 变量名:被遍历的Collection或者数组)   
{
}
//Map没继承Iterable接口 不能用
//集合中是什么类型,数据类型就写什么


局限性:
对集合进行遍历,只能获取元素,不能对集合进行操作
而Iterator除了遍历,可以remove()集合中的元素.
如果使用ListIterator 还可以在遍历过程中进行增删改查的操作.
传统for循环和高级for的区别:
高级for的局限性,必须有被遍历的目标:
比如将"hello world"打印100次 高级for无法做到


建议:
在遍历数组时 使用传统for


package pack;   
import java.util.*;
class Demo
{
public static void main(String[] args)  
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc");
al.add("chs");
al.add("hahaha");

for(String s: al)
{
sop(s);   
}
 
 
int[] arr={1,2,3,4,5};
for(int i:arr)
{
sop(i);
}

//Map不支持迭代,所以只能对其keySet 或者 entrySet 进行迭代
HashMap<Integer,String> hm = new HashMap<Integer,String>();
hm.put(1,"a");
hm.put(2,"b");
hm.put(3,"c");

 
Set<Integer> keys = hm.keySet();
for(Integer i: keys)
{
sop(i + " " + hm.get(i));
}


//entrySet 传统方法:
Set<Map.Entry<Integer,String>> entrySet = hm.entrySet();
for(Iterator<Map.Entry<Integer,String>> it = entrySet.iterator();it.hasNext();)
{
Map.Entry<Integer,String> me = it.next();
sop(me.getKey() + " " + me.getValue()); 
}
 
//entrySet 高级for
for(Map.Entry<Integer,String>me : hm.entrySet())
{
sop(me.getKey()+" "+me.getValue());
}

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}


 
 


 
 64 可变参数特性
 可变参数是数组的简写形式,不用每次一次都手动建立数组对象,
 只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组
注意!:可变参数只能写在参数列表最后面
 
 package pack;   
class Demo
{
public static void main(String[] args)  
{
show(2,3,4,5,6,100,0);
show2("abc",1,2,3);
}

public static void show(int... arr) // 相当于 int数组
{
for(int i:arr)
{
sop(i);
}
}

public static void show2(String str,int ...arr) //可变参数只能写在最后
{
sop(str);
for(int i:arr)
{
sop(i);
}
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}




 
65 导入静态函数:
每次写Collections Arrays等类时 经常要写Arrays. 很麻烦
import static java.util.Arrays.*;//导入Arrays类中所有静态成员
注意如果导入的方法中有重名方法或者变量时,还是要加包名才可以使用.


package pack;
import static  java.lang.System.*; 
  
class Demo
{
public static void main(String[] args)  
{
out.println("haha");
}
}


 


66 Runtime 类 (lang包)
这个是单例构造模式的
得到对象:Runtime.getRuntime();
Process exec(path); 能够打开系统中的程序,并返回打开的进程
Process 下有个有用的destroy() 能够杀死该进程
 
class Demo
{
public static void main(String[] args) throws Exception
{
Runtime r = Runtime.getRuntime();
Process p =  r.exec("D:\\Program Files\\duowan\\yy\\YY.exe"); //执行程序
Thread.sleep(4000);
p.destroy(); //杀死进程
}
}




67 Date 类 (java.util包)
SimpleDateFormat (java.text)


import java.util.*;
import java.text.*;


class Demo
{
public static void main(String[] args) throws Exception
{
Date d = new Date();
System.out.println(d); //Tue Sep 10 09:27:43 CST 2013 当前时间

//将模式封装到 SimpleDateFormat对象中
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日,HH:mm:ss E");
//调用format方法,让模式格式化Date对象
String time = sdf.format(d);  
System.out.println(time);
}
}


68 Calendar 类 
get(field)  获得时间信息


import java.util.*;
class Demo
{
public static void main(String[] args) throws Exception
{
Calendar c = Calendar.getInstance(); //获得当前时间的实例
sop(c);
sop("");
int year = c.get(Calendar.YEAR);
sop("year "+ year);
int month = c.get(Calendar.MONTH);
sop("month "+ (month+1));// 计算机的月从0开始的 是0~11
int day = c.get(Calendar.DAY_OF_MONTH);
sop("day "+day);
int dayofweek = c.get(Calendar.DAY_OF_WEEK); //老外的第一天是周日
sop(dayofweek);

//使用查表法打印时间
String[] arry_month = {"一月","二月","三月","四月","五月","六月",
"七月","八月","九月","十月","十一月","十二月"};
String[] arry_dayofweek={"","星期天","星期一","星期二","星期三","星期四",
"星期五","星期六"}; 
sop(year+"年"+arry_month[month]+day+"日"+arry_dayofweek[dayofweek]);

}

public static void  sop(Object obj)
{
System.out.println(obj);
}
}


 void set(int year, int month, int date) 
          设置日历字段 YEAR、MONTH 和 DAY_OF_MONTH 的值。 
 void set(int year, int month, int date, int hourOfDay, int minute) 
          设置日历字段 YEAR、MONTH、DAY_OF_MONTH、HOUR_OF_DAY 和 MINUTE 的值。 
 void set(int year, int month, int date, int hourOfDay, int minute, int second) 
          设置字段 YEAR、MONTH、DAY_OF_MONTH、HOUR、MINUTE 和 SECOND 的值。 
abstract  void add(int field, int amount) 
          根据日历的规则,为给定的日历字段添加或减去指定的时间量。 




 
import java.util.*;
class Demo
{
public static void main(String[] args) throws Exception
{
Calendar c = Calendar.getInstance();
c.set(2012,2,13); //设置时间 2012-3-13日 
printDate(c);//2012年三月13日星期二

//时间的偏移
c.add(Calendar.MONTH,3); //增加三个月
printDate(c);//2012年六月13日星期三

c.add(Calendar.MONTH,-6); //减去6个月
printDate(c);//2011年十二月13日星期二


}

public static void  sop(Object obj)
{
System.out.println(obj);
}
public static  void printDate(Calendar c)
{
//使用查表法打印时间
String[] arry_month = {"一月","二月","三月","四月","五月","六月",
"七月","八月","九月","十月","十一月","十二月"};
String[] arry_dayofweek={"","星期天","星期一","星期二","星期三","星期四",
"星期五","星期六"}; 

sop(c.get(Calendar.YEAR)+"年"+
arry_month[c.get(Calendar.MONTH)]+
c.get(Calendar.DAY_OF_MONTH)+"日"+
arry_dayofweek[c.get(Calendar.DAY_OF_WEEK)]);

}
}


69 Math (java.lang)
abs 返回绝对值
ceil  返回大于给定数的最小整数
floor 返回小于给定数的最大整数
round 四舍五入
pow 幂数运算
random 0~1的随机数


Random (java.util)
Random()
nextInt()
 
 
 import java.util.*;
class Demo
{
public static void main(String[] args) throws Exception
{
sop(Math.abs(-1));//1
sop(Math.ceil(12.14));//取天花板13.0
sop(Math.floor(12.14));//取地板 12.0

sop(Math.round(12.14)); //做四舍五入

Double d = Math.pow(2,3); //2的三次方
sop(d);

for(int x=0;x<10;x++)
{
Double d2 = Math.random(); //0~1之间的随机数
sop(d2);
}

//1~10的随机数
for(int x=0;x<10;x++)
{
int y = (int)(Math.random()*10 + 1); //1~10 的随机数
sop(y);
}
sop("Random");

//Random类的随机数
Random r = new Random();
for(int x=0;x<10;x++)
{
int y = r.nextInt(10)+1; //1~10 的随机数 : r.nextInt(10) 是0~9的随机数 
sop(y);
}
}

public static void  sop(Object obj)
{
System.out.println(obj);
}
}








 
 
70 IO
字符流和字节流
字节流两个基类:
InputStream OutputStream
字符流两个基类:
Reader Writer


71 字符流
Writer
|--FileWriter
找到一个专门用于操作文件的子类对象FileWriter


 import java.io.*;
class Demo
{
public static void main(String[] args) throws IOException
{
//创建一个FileWriter对象,该对像一被初始化就必须要申明被操作的文件
//而且该文件会被创建到指定目录,如果已存在,则覆盖
//其实该步就是明确数据存放的目地地
FileWriter fw = new FileWriter("abc.txt");
//调用write方法,将字符串写入流中
fw.write("abcde");
//将流中的文件写入文件
fw.flush();
//继续写 会写在abcde的后面
fw.write("123");
//关闭流资源,关闭之前会flush一次流中的数据,将数据写入文件
fw.close();
//和flush的区别:close之后不可以再写. 
}
 
}


72 对IO异常处理
FileWriter中write flush close 都可能抛出异常,所以要对它们进行异常处理.




import java.io.*;
class Demo
{
public static void main(String[] args)  
{
FileWriter fw = null;  //1将流对象定义在块外面 并用null初始化它
try
{
fw = new FileWriter("K:\\abc.txt");   //2 创建流对象和write放在try块中
fw.write("abcde");
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try //3 close写在finally中,但是在关闭前一定要检查流是否创建成功
{
if(fw != null)
{
fw.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
 
}




73 文件的续写
FileWriter(String fileName, boolean append) 
          根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。


 
import java.io.*;
class Demo
{
public static void main(String[] args)  
{
FileWriter fw = null;
try
{
fw = new FileWriter("abc.txt",true);

fw.append("哈哈");
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(fw != null)
{
fw.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
 
}


74 读取文件


FileReader(File file) 
          在给定从中读取数据的 File 的情况下创建一个新 FileReader
 int read()
          读取单个字符。  返回读到的字符
 int read(char[] cbuf) 
          将字符读入数组。 返回读取到的字符个数
读到结尾返回-1
 
 
import java.io.*;
class Demo
{
public static void main(String[] args) throws IOException
{

//创建一个文件读取流对象,和指定名称的文件相关联
//要保证该文件是已经存在的,如果不存在会发生异常
FileReader fr = new FileReader("abc.txt");
//read()读取出一个字符,当读取到末尾时返回-1
int ch;
while((ch = fr.read())!= -1)
{
System.out.println("ch="+(char)ch);
}
fr.close();

}


另外也可以一大块字符地读
import java.io.*;
class Demo
{
public static void main(String[] args)  

FileReader fr = null;
try
{
fr = new FileReader("123.java");
char[] buf = new char[1024];
while(fr.read(buf)!= -1)
{
System.out.print(buf);  //不要写println 不要在不该换行时换行
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(null != fr)
{
fr.close();
}
}
catch(IOException e)
{
System.out.println(e.toString());
}

}
}
 
}


拷贝文件
import java.io.*;
class Demo
{
public static void main(String[] args)  
{
FileReader fr = null;
FileWriter wr = null;
try
{
fr = new FileReader("123.java");
wr = new FileWriter("abc.txt");
char[] buf = new char[1024];
int n = 0;
while((n = fr.read(buf))!= -1)
{
wr.write(buf,0,n); //读多少写多少
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{

//两个关闭的try分开写
try
{
if(null != fr)
{
fr.close();
}
}
catch(IOException e)
{
System.out.println(e.toString());
}


try
{
if(null != wr)
{
wr.close();
}
}
catch(IOException e)
{
System.out.println(e.toString());
}

}
}
}




75  BuffererWriter 字符写入缓冲区
提供一个缓冲区 来让Writer进行高效写入


BufferedWriter(Writer out) 
          创建一个使用默认大小输出缓冲区的缓冲字符输出流。
void close() 
          关闭此流,但要先刷新它。 
 void flush() 
          刷新该流的缓冲。 
 void newLine() 
          写入一个行分隔符。 (跨平台 ,只有缓冲区有) 
 void write(char[] cbuf, int off, int len) 
          写入字符数组的某一部分。 
 void write(int c) 
          写入单个字符。 
 void write(String s, int off, int len) 
          写入字符串的某一部分 


import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
//创建一个字符写入流对象
FileWriter fw = new FileWriter("abc.txt");
//为了提高字符写入流效率,加入缓冲技术
//只要将需要被提高效率的流传递给缓冲区的构造函数
BufferedWriter bufw = new BufferedWriter(fw);

//往缓冲区写入 
bufw.write("abcde");
bufw.newLine();
bufw.write("1123");

//记住 只要用到缓冲区,就要记得刷新 让内容写入文件
bufw.flush();
//关闭缓冲区实际是 关闭缓冲区中的流对象
bufw.close();

}
}


76 BufferedWriter 字符读取缓冲区
BufferedReader(Reader in) 
          创建一个使用默认大小输入缓冲区的缓冲字符输入流。
方法摘要 
 void close() 
          关闭该流并释放与之关联的所有资源。 
 int read() 
          读取单个字符。 
 int read(char[] cbuf, int off, int len) 
          将字符读入数组的某一部分。 
 String readLine() 
          读取一个文本行。 不返回回车符. 当到文件末尾时 返回null
 
 
import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
FileReader fr = new FileReader("123.java");
BufferedReader br = new BufferedReader(fr);

//除了读1个 读1个数组 还有个特有的 readLine
String line = null;
while((line=br.readLine() )!= null)
{
System.out.println(line);
}

br.close();
}
}


77 使用缓冲区复制文件
import java.io.*;
class Demo
{
public static void main(String[] args)  
{

FileReader fr = null;
FileWriter fw = null;
BufferedReader br = null;
BufferedWriter bw = null;
try
{
fr = new FileReader("123.java");
fw = new FileWriter("abc.txt");
   br = new BufferedReader(fr);
bw = new BufferedWriter(fw);

//除了读1个 读1个数组 还有个特有的 readLine
String line = null;
while((line=br.readLine() )!= null)
{
bw.write(line );   
bw.newLine();  //需要加入换行
bw.flush();
}

}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(br != null)
{
br.close();
}
}
catch(IOException e)
{
System.out.println(e.toString());
}

try
{
if(bw != null)
{
bw.close();
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}


79 MyBufferReder 自定义的一个Reader缓冲类


import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
 
FileReader fr = new FileReader("123.java");
MyReaderBuffer br = new MyReaderBuffer(fr);

//除了读1个 读1个数组 还有个特有的 readLine
String line = null;
while((line=br.readLine() )!= null)
{
System.out.println(line);
}

br.close();
}
}


class MyReaderBuffer extends Reader
{
private Reader r;
MyReaderBuffer(Reader r)
{
this.r = r;
}

//提供增强方法
public String readLine() throws IOException
{
StringBuilder sb = new StringBuilder();
int ch = 0;
boolean rflag = false;
while((ch=r.read()) != -1)
{
if(ch == '\r')
{
continue;
}

if(ch == '\n')
{
return sb.toString();
}

sb.append((char)ch);

}

if(sb.length() != 0)
{
return sb.toString();
}
else
return null;
}

//下面是Reader接口中的两个抽象方法

public int read(char[] cbuf, int off, int len) throws IOException
{
return r.read(cbuf,off,len);
}

public void close() throws IOException
{
r.close();
}
}




80 装饰设定模式
当想要对已有的对i昂进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强方法
那么自定义的该类成为装饰类
装饰类通常会通过构造方法接收被接收的对象,并基于被装饰对象的功能,提供更强的功能.
一般来说装饰类和被装饰类属于同一个体系




import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
Person p = new Person();
SuperPerson sp = new SuperPerson(p);
sp.chifan();
 
}
}


class Person
{
void chifan()
{
System.out.println("吃饭");
}


}


class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p = p;
}

void chifan()
{
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
}
}


81 LineNumerReader 装饰类
java.lang.Object
  java.io.Reader
      java.io.BufferedReader
          java.io.LineNumberReader
可以给输出内容标记行号  操作和BufferedReader差不多  


import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
FileReader fr = new FileReader("abc.txt");
LineNumberReader lnr = new LineNumberReader(fr);
lnr.setLineNumber(100); // 将起始行号设置为10 
//第一个行号便显示为10 但是显示的内容实际还是从第一行开始的
String line = null;
while((line=lnr.readLine()) != null)
{
System.out.println(lnr.getLineNumber() + line); //输出行号 + 内容
}

lnr.close();
}
}
   


82 字符流总结
FileReader
FileWriter
BufferedReader
BufferedWriter
LineNumberReader


83 字节流
FileInputStream 
FileOutPutStream
BufferedInputStream 
BufferedOutStream


需求 想要操作图片数据 就要用到字节流
 
 
//字节写入文件
import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
//创建一个写入流
FileOutputStream fos = new FileOutputStream("fos.txt");
//只能写字节 或者 字节数组
fos.write("abcdef".getBytes());
fos.close();
}
}


//字节读取文件


import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
//读取文件 方法1 (一个个读 慢)
FileInputStream fis1 = new FileInputStream("fos.txt");
int ch = 0;
while((ch=fis1.read()) != -1)
{
System.out.print((char)(ch));
}
System.out.println("");

//方法2 (折中,推荐使用)
FileInputStream fis2 = new FileInputStream("fos.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis2.read(buf)) != -1)
{
System.out.print(new String(buf,0,len));
}
System.out.println("");

//方法3 (如果数据太大,不建议使用)
FileInputStream fis3 = new FileInputStream("fos.txt");
int size = fis3.available(); //获得可以读取到
byte[] buf2 = new byte[size];
fis3.read(buf2);
System.out.print(new String(buf2));


  fis1.close();
fis2.close();
fis3.close();
}
}






84 拷贝一个图片


import java.io.*;
class Demo
{
public static void main(String[] args)   
{
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
fis = new FileInputStream("1.jpg");
fos = new FileOutputStream("2.jpg");

byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf)) != -1)
{
fos.write(buf,0,len);
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
fis.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}

try
{
fos.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}


85 缓冲区字节流


import java.io.*;
class Demo
{
public static void main(String[] args)   throws IOException
{
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
System.out.println(end-start); //运行时间

}

public static void copy_1() throws IOException
{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("F:\\知足-五月天.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("F:\\知足.mp3"));
int ch = 0;
while((ch=bufis.read()) != -1)
{
bufos.write(ch); 
//如果每步都flush() 会慢爆了...
}

bufis.close(); 
bufos.close(); //关闭时 自动flush

}
}




86 读取键盘输入
获取InputStream对象
InputStream in = System.in;




import java.io.*;
class Demo
{
public static void main(String[] args)   throws IOException
{
InputStream in = System.in;
int by = in.read(); //read是个阻塞函数
int by2 = in.read(); //回车有两个字符 \r\n
int by3 = in.read();

System.out.println(by);
System.out.println(by2);
System.out.println(by3);
}
}


 
 87 
 当录入一行数据后就将改行数据打印
 如果录入的是over,那么停止录入.


import java.io.*;
class Demo
{
public static void main(String[] args)   throws IOException
{
InputStream in = System.in;
int ch = 0;
StringBuilder sb = new StringBuilder(); //可变长度的缓冲区
while(true)
{
ch = in.read();

if(ch == '\r') continue; 
if(ch == '\n')
{
int len = sb.length();
String s = sb.toString();
if(s.toUpperCase().equals("OVER"))
{
break;
}
else
{
sb.delete(0,len); //回车后 若未结束 则清空缓冲区
}
}
else
sb.append((char)(ch));
}
}
}
 


88  InputStreamReader(InputStream) 转换流 (字节流变字符流)
outPutStreamWriter (OutputStream)


//键盘录入最常见写法


import java.io.*;
class Demo
{
public static void main(String[] args)   throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;
while((line=br.readLine()) != null)
{
if("over".equals(line)) break;
bw.write(line,0,line.length());
bw.newLine();
bw.flush();
}
}
}
 
89 改变标准输入输出
static void setIn(InputStream in) 
          重新分配“标准”输入流。 
static void setOut(PrintStream out) 
          重新分配“标准”输出流。 


import java.io.*;
class Demo
{
public static void main(String[] args)   throws IOException
{
System.setOut(new PrintStream("zz.txt")); //将输出流修改

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;
while((line=br.readLine()) != null)
{
if("over".equals(line)) break;
bw.write(line,0,line.length());
bw.newLine();
bw.flush();
}
}
}


90 异常的日志信息
将异常信息保存在文件中


import java.io.*;
import java.util.*;
import java.text.*;
class Demo
{
public static void main(String[] args)   throws  Exception
{
try
{
int[] arr = new int[2];
int a = arr[3];
}
catch(Exception e)
{
try
{
Date d = new Date();
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d);
PrintStream ps = new PrintStream("log.txt");
System.setOut(ps);
System.out.println(time);
e.printStackTrace(ps);
}
catch(Exception e2)
{
throw new Exception("日志文件创建失败");
}
}

}
}


除了自己写一个log类外 还有个log4j的开源项目提供日志功能


91 将系统信息打印到文本
import java.io.*;
import java.util.*;
 
class Demo
{
public static void main(String[] args)   throws  Exception
{
Properties prop = System.getProperties();
prop.list(System.out); //打印到输出
prop.list(new PrintStream("prop.txt")); //打印到文本
}
}


92 File对象
 创建File对象
 
 File(File parent, String child) 
          根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 
File(String pathname) 
          通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 
File(String parent, String child) 
          根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例 


 static String separator 
          与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。  


import java.io.*;
import java.util.*;
 
class Demo
{
public static void main(String[] args)   throws  Exception
{
//将已有或者未出现的文件或者文件夹封装成对象

//以下三种方法是等效的:
File f1 = new File("c:\\abc\\b.txt"); //路径
File f2 = new File("c:\\abc","b.txt"); //父目录和文件名分开写

File d = new File("c:\\abc");
File f3 = new File(d,"b.txt"); 

sop("f1:"+f1);
sop("f2:"+f2);
sop("f3:"+f3);

//File.separator 分隔符 WIN下是\\ LInux下是/
File f4 = new File("c:"+File.separator+"abc"+File.separator+"b.txt");
sop("f3:"+f4);

}

public static void  sop(Object obj)
{
System.out.println(obj);
}
}
 
 
 
 93 File类常用方法
 1 创建
 public boolean createNewFile():
 在指定位置创建文件,如果文件已经存在,则不创建
 和输出流不一样,输出流对象一建立就会自动创建且覆盖文件
 static File createTempFile(String prefix, String suffix) 
          在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称 


//重命名
 public boolean renameTo(File dest)重新命名此抽象路径名表示的文件。 
 
 
 2 删除
  boolean delete() 
          删除文件或目录。  
 void deleteOnExit() 
          在虚拟机终止时,删除文件。 


 3 判断
 
 boolean exists() 
          测试此抽象路径名表示的文件或目录是否存在。 
 
 boolean canExecute() 
          测试应用程序是否可以执行此抽象路径名表示的文件。 
 boolean canRead() 
          测试应用程序是否可以读取此抽象路径名表示的文件。 
 boolean canWrite() 
          测试应用程序是否可以修改此抽象路径名表示的文件。 
 boolean isDirectory() 
          测试此抽象路径名表示的文件是否是一个目录。 
 boolean isFile() 
          测试此抽象路径名表示的文件是否是一个标准文件。 
 boolean isHidden() 
          测试此抽象路径名指定的文件是否是一个隐藏文件。 


 boolean isAbsolute() 
          测试此抽象路径名是否为绝对路径名 
 
 4 获取信息
//获取路径
String getPath() 
          将此抽象路径名转换为一个路径名字符串。 (封装的是什么path就是什么path)
File getAbsoluteFile() 
          返回此抽象路径名的绝对路径名形式。  返回File对象
String getAbsolutePath() 
          返回此抽象路径名的绝对路径名字符串。 
//获取父目录
 String getParent() 
          返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。 
 File getParentFile() 
          返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。 
//获取名称
 String getName() 
          返回由此抽象路径名表示的文件或目录的名称 
//其他
 long lastModified() 
          返回此抽象路径名表示的文件最后一次被修改的时间。 
 long length() 
返回由此抽象路径名表示的文件的长度。以字节为单位
import java.io.*;
import java.util.*;
import java.text.*;
 
class Demo
{
public static void main(String[] args)   throws  Exception
{
//创建文件夹
//1创建1个目录
File d = new File("abc");
sop(d.mkdir());

//2创建目录并创建其不存在父目录
File d2 = new File("123"+File.separator+"456");
sop(d2.mkdirs());


//创建文件
File f = new File("123\\file.txt"); //一定要文件所在目录存在
sop("create:"+f.createNewFile());
//判断文件是否是文件或者是目录时,必须要先判断该文件封装的内容是否存在
//若文件不存在,isFile() .isDirectory()都返回false
sop("exist:"+f.exists());
sop("is File:"+f.isFile());
sop("is dir:"+f.isDirectory());

//f.deleteOnExit();

//获取信息
sop("path:"+f.getPath()); //path:123\file.txt
sop("abs path"+f.getAbsolutePath());//abs pathF:\\123\file.txt
sop("parent:"+f.getParent());//返回绝对路径下的父目录.
//如果封装的是没有写父目录的相对路径,返回空
sop("name"+f.getName()); 
long last = f.lastModified();
Date date  = new Date(last);
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
sop("last modified:"+sdf.format(date));
sop("length:"+f.length());

//重命名
File f1 = new File("f:\\zzz.txt");
File f2 = new File("d:\\zz.txt");
sop(f1.renameTo(f2));

}

public static void  sop(Object obj)
{
System.out.println(obj);
}
}


94 文件列表


 String[] list() 
          返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 
 String[] list(FilenameFilter filter) 
          返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
 
 File[] listFiles() 
          返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 
 File[] listFiles(FileFilter filter) 
          返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 
 File[] listFiles(FilenameFilter filter) 
          返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 
 
static File[] listRoots() 
          列出可用的文件系统根 


 
 


import java.io.*;
class Demo
{
public static void main(String[] args)   throws  Exception
{
listRoots();
listFiles();

}

public static void listRoots()
{
File[] roots = File.listRoots(); //获取所有盘符
for(File f:roots)
{
sop(f.toString());
}
}

public static void listFiles()
{
File c = new File("c:\\"); //封装的是文件或不存在的目录返回空
File[] files = c.listFiles();
if(files != null)
{
for(File f:files)
{
sop(f.toString());
}
}
}
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


95 打印所有txt文件


import java.io.*;


class Demo
{
public static void main(String[] args)   throws  Exception
{

print1();
sop("-------");
print2();

}
 
public static void  sop(Object obj)
{
System.out.println(obj);
}

//使用list() 获得String 
public static void print1()
{
File dir = new File("f:\\");
String[] arr = dir.list(
new FilenameFilter() //内部匿名类(实现 FilenameFilter 接口,注意这种写法)
{
public boolean accept(File dir,String name)
{
if(name.endsWith(".txt"))
{
return true;
}
else
return false;
}
}
);
for(String name: arr)
{
sop(name);
}

}

//使用listFiles 获取文件对象 可以顺便对文件操作
public static void print2()
{
File dir = new File("f:\\");
File[] arr = dir.listFiles(
new FilenameFilter() //内部匿名类(实现 FilenameFilter 接口,注意这种写法)
{
public boolean accept(File dir,String name)
{
if(name.endsWith(".txt"))
{
return true;
}
else
return false;
}
}
);
for(File file: arr)
{
sop(file.toString() + " " + file.length());
}

}
}






96 遍历文件夹内容




import java.io.*;


class Demo
{
public static void main(String[] args)   throws  Exception
{
showDir(new File("F:\\安卓视频"),0);
}

public static void showDir(File dir,int x)
{
if(!dir.isDirectory())
{
sop(getLevel(x)+dir.getName());
return;
}

File[] files = dir.listFiles();
for(File file:files)
{
showDir(file,++x);
x--;
}

}


public static String getLevel(int lev)
{
StringBuilder sb = new StringBuilder();
for(int x=0;x<lev;x++)
{
sb.append('\t');
}

return sb.toString();
}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}

 
}




97 删除带内容的目录
//目录必须为空才能删除 
//所以要删除里面内容才能删除目录 使用递归方法
import java.io.*;


class Demo
{
public static void main(String[] args)   throws  Exception
{
File f = new File("f:\\abc");
removeDir(f);
}

public static void removeDir(File dir)
{
if(dir.isDirectory())
{
File[] files = dir.listFiles();

for(File f : files)
{
if(f.isDirectory())
{
removeDir(f);
}
f.delete();
}
}

dir.delete();
}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}

 
}


98  打印目录下所有java文件,并存放在文件中
import java.io.*;
import java.util.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
ArrayList<String> al  = new ArrayList<String>();
File f = new File("f:\\abc");
listJava(f,al);
writeToFile("f:\\javalist.txt",al);
}

public static void listJava(File dir,ArrayList<String> al)
{
if(dir.isDirectory())
{
File[] files = dir.listFiles();
for(File f : files)
{
if(f.isDirectory())
{
listJava(f,al);
}
else
{
String filename = f.toString();
//sop("list:"+filename);
if(filename.endsWith(".java"))
{
al.add(filename);
}
}
}
}
}
 
public static void writeToFile(String filepath,ArrayList<String> al) throws Exception
{
BufferedWriter bw = null;
try
{
Iterator<String> it = al.iterator();
bw = new BufferedWriter(new FileWriter(filepath));
while(it.hasNext())
{
String line = it.next();
bw.write(line,0,line.length());
bw.newLine();
}
}
catch(IOException e)
{
sop(e.toString());
throw new Exception("文件操作异常");
}
finally
{
if(bw != null)
{
try
{
bw.close();
}
catch(IOException e)
{
sop(e.toString());
}
}

}
}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


99 Properties
Properties 是 HashTable 的子类 
具有Map的所有特性 ,是由<String,String>键值对构成
该对象的特点:可以用于读取键值对形式的配置文件


1)添加和获取元素:
 String getProperty(String key) 
          用指定的键在此属性列表中搜索属性。 
 Object setProperty(String key, String value) 
          调用 Hashtable 的方法 put。 
 Set<String> stringPropertyNames() 
          返回此属性列表中的键集,其中该键及其对应值是字符串  


import java.util.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
setAndGet();
}

//设置和获取元素
public static void setAndGet()
{
//设置属性
Properties prop = new Properties();
prop.setProperty("张三","30");
prop.setProperty("李四","32");
//sop(prop);
//sop( "李四:" + prop.getProperty("李四") ); 

//遍历 获取元素

Set<String> keys = prop.stringPropertyNames(); //获取所有的键
/* //方法一 迭代器
Iterator<String> it = keys.iterator();
while(it.hasNext())
{
String key = it.next();
sop(key+" "+prop.getProperty(key));
}
*/

prop.setProperty("李四","89"); //修改元素
//方法二 高级for
for(String s:keys)
{
sop(s+" "+prop.getProperty(s));
}


}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


2) 将流中的数据存储到集合中


import java.util.*;
import java.io.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
//创建一个字符流 1.6开始也可以是字节流 文件中一定要是=或者:分割的键值对
FileReader fr = new FileReader("配置.txt");
//创建Properties对象
Properties prop = new Properties();
//load流,就可以了
prop.load(fr);
fr.close();
//打印
prop.list(System.out); //打印出所有的键值对
//修改
prop.setProperty("abc","19");
prop.list(System.out);
//保存
//FileOutputStream fos = new FileOutputStream("配置.txt");
FileWriter fw = new FileWriter("配置.txt");
prop.store(fw,"zhaoyihong"); //前面是流 后面是注释

fw.close();
}


public static void  sop(Object obj)
{
System.out.println(obj);
}
}


100 打印流 (重要)
该流提供了打印方法,可以将各种数据类型的数据都原样打印
打印字节流:
PrintStream
构造函数:
1File对象 
2字符串路径
3字节输出流


PrintWriter
构造函数:
1File对象 
2字符串路径
3字节输出流
4字符输出流Writer
 
 import java.util.*;
import java.io.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
//读取键盘对象
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//向控制台输出
//PrintWriter out = new PrintWriter(System.out,true); //可以自动刷新

//向文件输出
//PrintWriter out = new PrintWriter("a.txt");
//向文件输出时 想要自动刷新 则先把文件封装到流里面
PrintWriter out = new PrintWriter(new FileOutputStream("a.txt"),true);

String line = null;
while((line=bufr.readLine()) != null)
{
if("over".equals(line)) break;
out.println(line.toUpperCase());
//out.flush();
}

out.close();
}

public static void  sop(Object obj)
{
System.out.println(obj);
}
}


101 SequenceInputStream 
多个流对应一个目地时,先把流封装成一个,再写入目地
应用有比如三个文件变成一个文件
合并文件


 
import java.util.*;
import java.io.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
Vector<InputStream> v= new Vector<InputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<InputStream> e = v.elements();
SequenceInputStream sis = new SequenceInputStream(e);


FileOutputStream fos =  new FileOutputStream("4.txt");

byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf,0,buf.length)) != -1)
{
fos.write(buf,0,len);
}

sis.close();
fos.close();  
}
}


102 对象的序列化
ObjectOutputStream 
ObjectInputStream


序列化是将对象状态转换为可保持或传输的格式的过程,它也是RMI用来在不同JVM之间传递对象的机制,或者通过方法的参数或者作为一个方法调用的返回值。但有三个例外序列化不需要读或者写入到流:


1. 序列化会忽略静态字段,因为他们不属于对象的任何状态。


2. 基类的字段只有基类本身是序列化的时候才能被序列化。


3. 瞬间字段(transient)


记住:没有被序列化的字段 不会被写入流.
读取出来的值的特征:






对象序列化包括如下步骤:


1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;


2) 通过对象输出流的writeObject()方法写对象。


对象反序列化的步骤如下:


1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;


2) 通过对象输入流的readObject()方法读取对象。


//person.java


import java.io.*;


class Person implements Serializable 
{
private String name;
private transient int  age;
static String country = "cn";
Person(String name,int age,String country)
{
this.name = name;
this.age = age;
this.country = country;  
}

public String toString()
{
return name+":"+age+":"+country;
}


}




//-------------------------


import java.io.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
//writeObj();
readObj();
 
}

public static void writeObj()  throws IOException
{
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("obj.txt"));

Person p = new Person("zhangsan",22);


oos.writeObject(p);  
oos.close();

}

 
public static void readObj()  throws Exception
{
ObjectInputStream ois = 
new ObjectInputStream(new FileInputStream("obj.txt"));
Person p = (Person)(ois.readObject());
sop(p.toString());
/*
F:\>java Demo
zhangsan:0:cn //age 和 country都没有序列化
*/
}
 


public static void  sop(Object obj)
{
System.out.println(obj);
}
}


当然一个文件中也可以存多个类


103 管道流
PipedInputStream 
PipedOutputStream


可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态。 




 




import java.io.*;


class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream i)
{
this.in = i;
}

public void run()
{
try
{
byte[] buf = new byte[1024];
int len = in.read(buf); //阻塞方法
String s = new String(buf,0,len);
Demo.sop(s);
}
catch(IOException e)
{
throw new RuntimeException("管道流读取失败");
}
finally
{
if(in != null)
{
try
{
in.close();
}
catch(IOException e)
{
throw new RuntimeException("管道流关闭失败");
}
}
}
}
}




class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}

public void run()
{
try
{
out.write("hahaha".getBytes());
out.close(); //写简单点了
}
catch(IOException e)
{
throw new RuntimeException("管道流写入失败");
}
}
}








class Demo
{
public static void main(String[] args)   throws Exception
{

PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out); //将两个管道连接起来
Read r = new Read(in);
Write w = new Write(out);

new Thread(r).start();
new Thread(w).start();
 
}
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}




104 RandomAccessFile
java.lang.Object
  java.io.RandomAccessFile


该类不算IO体系中的子类,而是直接继承Object
但是它是IO包中的成员,因为它具备读和写功能.
内部封装了一个数组,而且通过指针对数组的元素进行操作.
可以通过getFilePointer获取指针位置
同时可以通过seek改变指针的位置


其实完成读写的原理就是内部封装了字节输入和输出流


局限性: 只能操作文件
RandomAccessFile(File file, String mode) 
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 
RandomAccessFile(String name, String mode) 
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
mode
"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。  
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。  
 
构造的文件若不存在会创建,若存在不会覆盖
 希望存入的数据每条是固定长度的,以便于读取


import java.io.*;
class Demo
{
public static void main(String[] args)   throws Exception
{


write();
read();
}
public static  void read() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
sop("name "+name);
int age =  raf.readInt();
sop("age:"+age);

//特性1 :可以调整指针 移到开头
raf.seek(0);
raf.read(buf);
sop("name:"+new String(buf)); //李四

//特性2 :跳过字节
raf.skipBytes(4); //只能往后跳 不能往前跳
raf.read(buf);
sop(new String(buf)); //王五

//特性3 :随机写
raf.seek(8*2); //每条数据8字节
raf.write("张三".getBytes());
raf.writeInt(20);
raf.close();
}
 
 
public static void write() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(102);
raf.close();
}
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


105 操作基本数据类型(int byte char double boolean等)数据的流对象
DataInputStream DataOutputStream


import java.io.*;
class Demo
{
public static void main(String[] args)   throws Exception
{
DataOutputStream  dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(1.23456);
dos.write("张三".getBytes(),0,4);
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
sop(dis.readInt());
sop(dis.readBoolean());
sop(dis.readDouble());
byte[] buf = new byte[4];
dis.read(buf);
sop(new String(buf));
dos.readUTF
dis.close();
}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


106 封装了可变程度字节数组的流
ByteArrayInputStream 
在构造时需要接收数据源,且字节源是个字符数组




ByteArrayOutputStream
构造时不用定义数据源,因为对象内部已经封装了一个可变场字节数组,这就是数据的目的地.


因为这两个流对象都操作的是数组,所以没有使用系统资源 所以不用进行close关闭


import java.io.*;
class Demo
{
public static void main(String[] args)    
{
//数据源
ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());

//数据目地
ByteArrayOutputStream bos = new ByteArrayOutputStream();

int by = 0;
while((by=bis.read()) != -1)
{
bos.write(by);
}

sop(bos.size());
sop(bos.toString());

 
}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


IO
源:
键盘System.in 硬盘FileStream 内存ArrayStream
目地:
键盘System.out 硬盘FileStream 内存ArrayStream


 107 操作字符数组的流对象 (字符流)
CharArrayReader 
CharArrayWriter 


操作字符串的流对象
StringReader 
StringWriter 


108 流的编码
默认编码 unicode
常用UTF-8 gbk


由于字符流中不能设置编码
所以字符流若要设置编码需要采用字节流转字符流(OutputStreamWriter InputStreamReader)的形式
记住 存进去什么编码 取出来就要是什么编码 否则会出现乱码


import java.io.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
writeText();
readText();
 
}
 
public static void writeText() throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
 
public static void readText() throws IOException
{
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"UTF-8");
char[] buf = new char[10];
int len = isr.read(buf);
sop("len="+len);
sop(new String(buf,0,len));
}
 
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}


 






109 字符编码
Java默认是unicode
常用的还有 gbk , utf-8




编码:字符串变字节数组
String->byte[]
str.getBytes();
str.getBytes(charsetName);


解码:字节数组变字符串
byte[] -> String
new String(b)
new String(b,charsetName)




import java.io.*;
import java.util.*;
class Demo
{
public static void main(String[] args)  throws IOException
{
String s = "你好";
byte[] b1= s.getBytes("utf-8");
//System.out.println(Arrays.toString(b1));//显示每个字节的值 
String s1 = new String(b1,"utf-8");
sop(s1);
}
 
public static void  sop(Object obj)
{
System.out.println(obj);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马javase笔记是一份比较详细的Java基础学习笔记,适合初学者或者复习巩固Java知识的人使用。这份笔记是作者在两年时间内多次复习Java后总结出来的,其中包括了不同老师的举例和作者自己的感悟。这份笔记的内容力求通俗易懂,同时也包括了方法区和JVM(Java Virtual Machine)的介绍。方法区是字节码文件加载时进入内存的区域,字节码文件由Java源文件编译而成。JVM是Java虚拟机,用来运行Java字节码文件,它的关键作用是屏蔽了不同操作系统之间的差异,使得相同的Java程序可以在不同的操作系统上得到相同的结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java基础笔记MarkDown版4万字肝吐血](https://download.csdn.net/download/qq_33865785/88275967)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【学习笔记/自用】黑马程序员javase2023版-基础](https://blog.csdn.net/qq_41014040/article/details/129164451)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值