JAVA基础3

来源:互联网 发布:中国软件协会培训中心 编辑:程序博客网 时间:2024/05/16 08:01
1、线程
(1)线程创建的第一种方式
public class Test
{
public static void main(String[] args){
MyThread mt = new MyThread();  //创建出一条线程
mt.start();    //让线程开启
}
}
class MyThread extends Thread
{
public void run(){
//......
}
}
(2)线程创建的第二种方式
public class Test
{
public static void main(String[] args){
MyThread mt = new MyThread();
Thread th1 = new Thread(mt);  //创建线程
Thread th2 = new Thread(mt);
th1.start();  //启动线程
th2.start();
}
}
class MyThread implements Runnable
{
private int num = 10;
public void run(){
if(num > 0){
System.out.println(num--);
}
}
}
/*
这两种方式创建线程的区别:
1、通过实现Runnable接口的方式来创建线程的好处在于还可以继承其他的类
  而通过继承Thread的方式来创建线程有很大局限性
2、通过实现Runnable接口的方式来创建线程,创建的多个线程可以共享一个
  对象,即上面的th1 th2可以共享执行一段代码,因为只有一个对象
  而继承Thread的方式创建两个线程,没办法实现这一效果,他们分别执行
*/


2、线程运行的几种状态。
创建状态:new时创建,start运行
运行状态:具备CPU执行资格和执行权限。sleep(time)或者wait()就进入冻结状态。
冻结状态:释放了CPU执行资格和执行权限。sleep(time)或者notify就进入运行状态。
阻塞状态:具备CPU的执行资格,不具备CPU的执行权。冻结状态结束后,就有可能进入阻塞状态。
 运行状态时也有可能进入阻塞状态。
消亡状态:run结束。


3、同步:一件事情接着一件事情做
   异步:多件事件都在进行,相互不影响。


多线程存在的异步问题
(1)同步代码块
public class ThreadDemo
{
public static void main(String[] args){
MyThread mt = new MyThread();
Thread th1 = new Thread(mt);
Thread th2 = new Thread(mt);
th1.start();
th2.start();
}
}
/*
使用synchronized(对象){} 来锁住代码块
如果两个不同线程都拿着同一个对象去开锁,那只能有一个能进去锁住的代码块
另外一个线程必须等待第一个线程退出后方能进去。
当然,如果两个不同的线程拿着不同的对象,不影响。
同步锁成立的条件:(1)共享代码部分必须有多条线程在执行
  (2)必须保证使用的是同一个锁对象
*/
class MyThread implements Runnable
{
private int num = 30;
Object obj = new Object();
public void run(){
while(true){
synchronized(obj){
if(num > 0){
System.out.println(num--);
}
}
}
}
}
(2)同步函数的方式
public class ThreadDemo
{
public static void main(String[] args){
MyThread mt = new MyThread();
Thread th1 = new Thread(mt);
Thread th2 = new Thread(mt);
th1.start();
th2.start();
}
}
class MyThread implements Runnable
{
private int num = 30;
public void run(){
show();
}
public synchronized void show(){  //同步函数的方式,使用的锁是this
if(num > 0){
System.out.println(num--);
}
}
}
//同步函数使用的锁是线程类对象this
//静态的同步函数(public static synchronized void show())使用的锁是该函数所在类的对象 
//即 MyThread.class


4、多线程间的通讯
(1)wait方法:使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。
   线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它,
这样它才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
wait会释放对象的锁。
Thread.sleep(100),在睡眠期间是不会释放对象的锁。
(2)notify或者notifyAll:notify唤醒任意一个具备该锁的wait中的线程。notifyAll是唤醒所有具备该锁
的wait中的线程。
但是那个被唤醒的线程没办法马上执行,还要等notify的线程释放对象锁。
所以notify或者notifyAll方法调用也必须放在synchronized方法或synchronized块中。
(3)join()方法,在主线程中执行 th.join();  那么主线程要等th线程执行完了才能往下执行
(4)yield()方法; 该线程让出CPU,让CPU切换到其他的线程。




5、String字符串
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1 == s2); // true 栈中的s1,s2都指向了堆里的常量池中的"abc"。常量池只有一个"abc"
System.out.println(s1 == s3); // false 栈中的s3指向了堆中的String对象,String对象里的成员变量指向常量池里//的"abc"。


6、字符串常用方法 String s = "abcdabhelo";
(1)求长度
s.length();   //注意和数组中的 arr.length属性区别开来
(2)根据下标返回字符
s.charAt(2);  // c
(3)根据字符或者字符子串找到其位置
s.indexOf('a');  // 0
s.indexOf('a', 2); // 4 从下标2开始往右找字符'a'
s.indexOf("ab");  // 0
s.indexOf("ab", 1);  // 4 和上面的原理一样
(4)反向查找
s.lastIndexOf('a');  // 4 从右边开始找第一个'a'
(5)是否以某些字符串开头
s.startsWith("abc");  // true
(6)是否以某些字符串结尾
s.endsWith("elo");   // true
(7)是否包含某些字符串
s.contains("dabh");  // true
(8)忽略大小写判断字符串相同
s.equalsIgnoreCase("AbcdaBHelo");  // true
(9)字符数组转为字符串
char[] arr = {'a','b','c','d','e'};
String str = new String(arr);  // abcde
str = new String(arr,1,3);  // bcd
(10)字符串转为字符数组
s.toCharArray(); // {'a','b','c','d','a','b'.....}
(11)字节数组转为字符串
byte[] arr = {'b','a','y','j'};
String str = new String(arr);  // bayj
str = new String(arr,1,3);  // ayj
(12)字符串转为字节数组
s.getBytes();
(13)基本数据类型转为字符串
String str = String.valueOf(5);   // "5"
String str = String.valueOf(3.5); // "3.5"
(14)替换
String str = s.replace('a','x');  // str="xbcdxbhelo"而s不变 s="abcdabhelo"
String str = s.replace("ab","xy"); // str="xycdxyhelo"
String str = s.replace('m','m'); //原串没有m字符的话,返回原串
(15)切割
String s = "hello,world,nihao";
String[] arr = s.split(",");  //arr[0]="hello" arr[1]="world" arr[2]="nihao"
(16)截取子串
String s = "abcdef";
String s1 = s.substring(2);  //cdef
String s2 = s.substring(2,4); //注意结果是cd 从第2个开始截取,截取到第3个
(17)转大小写
String s = "Hello Java";
s.toUpperCase();  //HELLO JAVA
s.toLowerCase();  //hello java  同样也是不会改变原来的s的值
(18)去两端空格
s.trim();
(19)比较字符串大小
String s1 = "abc";
String s2 = "abd";
s1.compareTo(s2);  //返回0表示相等 返回正数表示s1>s2 返回负数表示s1<s2


7、StringBuffer
特点   (1)长度可变
 (2)里面数据类型不定
 (3)无论任何类型的数据,最终都变为字符串。比如sb.append(new Object());//com.test.sb.Object@3e0ebb
StringBuffer sb = new StringBuffer("abc");
sb.append("12");
sb.append(true);                   //追加
System.out.println(sb.toString()); // abc12true
sb.insert(1,"qq");                 //插入
System.out.println(sb.toString()); // aqqbc12true


sb.delete(2,4);                    //包含头,不包含尾,所以删了2和3
System.out.println(sb.toString()); // aqc12true
sb.deleteCharAt(1);                //删除一个字符
System.out.println(sb.toString()); // ac12true

sb.replace(0,2,"hello");           //替换,同样是包含头,不包含尾
System.out.println(sb.toString()); //hello12true
sb.setCharAt(4,'m');
System.out.println(sb.toString()); //hellm12true


sb.reverse();                      //反转
System.out.println(sb.toString()); //*******注意****** eurt21mlleh
//开发中建议用StringBuilder代替StringBuffer,API是一样的。效率和安全性更好。


8、包装数据类型
boolean Boolean
char         Character
byte         Byte
short Short
int         Integer
long         Long
float         Float
double Double

基本数据类型转为字符串
(1) 12 + ""
(2) String.valueof(12);
字符串转为基本数据类型
(1) int i = Integer.parseInt("1234"); ==> i = 1234
(2) Integer integer = new Integer("10");
int i = integer.intValue();   ==> i = 10


十进制转其它进制
String binary = Integer.toBinaryString(110);  //十进制转二进制
String hex = Integer.toHexString(110);        //十进制转十六进制
String octal = Integer.toOctalString(110);    //十进制转八进制
其它进制转十进制
int num = Integer.parseInt("110", 2);  //二进制转为十进制
int num = Integer.parseInt("27", 8);   //八进制转为十进制
int num = Integer.parseInt("4a", 16);  //十六进制转为十进制


9、包装类型自动装箱和拆箱
//JDK1.5之后的新特性
Integer i = new Integer(10);
//JDK1.5之后可简写为
Integer i = 10;  //自动装箱(普通类型转为类类型) 其实在这里把 new Integer(10)省略为10


i = i + 5;  //首先先把i拆箱(类类型转为普通数据类型)为int类型,和5相加后的结果再装箱为Integer类型


10、集合,用来存储对象。数组,用来存储基本数据类型。
(1)Collection常用方法
Collection c = new ArrayList();
c.add("hello");
Collection c1 = new ArrayList();
c1.add(new Integer(10));
c1.add("java");
c.addAll(c1);
System.out.println(c.size());  // 3
System.out.println(c);  // hello  10  java
System.out.println(c.contains("java")); // true


c.remove("java");
System.out.println(c);  // hello 10
c1.clear();
c1.add("hello");
c.retainAll(c1);  //这个式子的返回值是true 将c和c1里相同的元素保存在c中
System.out.println(c); // hello
(2)迭代器iterator
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
(3)List常用方法
ArrayList al = new ArrayList();
al.add("hello");
al.add("world");
al.add("nihao");

al.add(1,"zhang");  // hello zhang world nihao

al.remove(3);   // hello zhang world

al.set(1,"nihao"); // hello nihao world

al.get(2);  // world
List list = al.subList(0,2); //list里面有hello nihao  同样是包含头不包含尾


List中特有的遍历方法
因为Collection中的遍历方法有很大的局限性,不能在遍历的同时对其进行添加操作等
所以就出现了ListIterator
ListIterator li = al.listIterator();
while(li.hasNext()){
Object obj = li.next();
if(obj.equals("hello")){
li.add("xixi");  //利用迭代器的增加方法,如果使用Iterator就没有该方法了
}
}
//假如下面这种做法是有问题的:
//假如a1里有4个对象,迭代器it只知道它有4个对象。那么后面ArrayList add进来了 迭代器
//也不知道有新增的对象,所有就会报错。
Iterator it = a1.iterator();
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("hello")){
a1.add("xixi");
}
}
(4)List接口下的类特点
ArrayList:底层是以数组的结构存在。查询和修改快,增加和删除慢。
LinkedList:底层是以链表的结构存在。查询和修改慢,增加和删除快。
List:存进去的对象有顺序的,可重复的。
Set:存进去的对象没有顺序的,不可重复的。
(5)LinkedList常用方法
JDK1.6之后可使用的方法
LinkedList link = new LinkedList();
link.add("hello");
link.add("world");
link.offerFirst("nihao");  // nihao hello world
link.offerLast("zhang");   // nihao hello world zhang
link.peekFirst();   //获得第一个元素 nihao
link.peekLast();    //获得最后一个元素 zhang
link.pollFirst();  //获得第一个元素 并且从链表中删除了第一个元素

link.pollLast();   //获得最后一个元素 并且从链表中删除了最后一个元素

(6)Set:集合,数据是不可重复,并且数据时无序的。

数据无序的:数据存进去和取出来的顺序不一定一致。


HashSet:最底层其实还是数组,一个对象首先经过hashCode算法,得到一个结果,然后去这个数组的这个

结果的位置找其内容,如果这个位置的原本的对象不equals新的这个对象,那么新的对象就会在这个位置的下面增加进来,原来的对象依然存在。总结为一句,首先先判断hasCode()是否一致,如果一致再判断是否equals,如果equals,那么该对象就已经存在,不会再存进去。

自定义对象实现HashSet:

public class 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 int hashCode() {
return name.hashCode() + age;
}

@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}

@Override
public boolean equals(Object obj) {
if(obj instanceof Person){
Person p = (Person) obj;
if(this.name.equals(p.name) && this.age == p.age){
return true;
}
}
return false;
}

}

TreeSet的使用:
TreeSet ts = new TreeSet();
ts.add("abd");
ts.add("bcd");
ts.add("abc");
//最后打印的结果是有序,这个有序指的是会把帮从小到大排列,结果是:abc,abd,bcd

自定义对象实现TreeSet:

因为TreeSet具备排序的功能,所以其往里增加的对象必须是实现了Comparable接口,重写compareTo方法

@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person p = (Person) o;
if(this.age > p.age)
return -1;
else if(this.age < p.age)
return 1;
else 
return 0;
} else {
throw new ClassCastException("类型转换错误");
}
}


11、泛型<>

List<Person> list = new ArrayList<Person>();

上面的意思是指,该List里面只能装Person类型的对象,把检测提前到编译时期。

泛型擦除:对源码进行编译时,通过泛型对类型进行检查。如果类型没有问题,就会编译成class文件。

class文件是不带泛型信息的,所以这种情况叫做泛型擦除。

(1)泛型类:

class Util<A>{

private A a;

public A getA(){

return a;

}

public void setA(A a){

this.a = a;

}

}

main:

Util<Person> util = new Util<Person>(); //这样创建对象。

注意:A只是一个标记而已,任何字符都可以。

(2)泛型方法:当你的方法的参数类型是不确定时使用,与类的类型没有关系。

class Demo{

public <A> void show(A a){

System.out.println(a);

}

}

main:

Demo d = new Demo();

d.show("hello");

d.show(12);

注意,如果是静态的方法上使用泛型,不能定义在类上,因为如果定义在类上,它必须通过对象才能确定类型。

而静态方法优先于对象存在。所以只能像上面这样,定义在方法上。

(3)泛型接口:

interface MyInterface<A>{

public void show(A a);

}

下面子类实现上面的接口,分为两种情况:

第一种,传入类型明确。

class Demo implements MyInterface<String>{

public void show(String s){


}

}

main:

Demo<String> demo = new Demo<String>();

demo.show("hello");

第二种,传入类型也不明确。

class Demo<K> implements MyInterface<K>{

public void show(K k){


}

}

main:

Demo<String> demo = new Demo<String>();

demo.show("hello");

Demo<Person> demo2 = new Demo<Person>();

demo.show(new Person());

(4)泛型通配符:?

第一种,就是普通的泛型方法。

public static <T> void myShow1(Collection<T> c){
Iterator<T> it = c.iterator();
while(it.hasNext()){
T t = it.next();
System.out.println("--->" + t);
}
}
第二种,利用泛型通配符,和上面的效果一样,但是用通配符更简便。
public static void myShow2(Collection<?> c){
Iterator<?> it = c.iterator();
while(it.hasNext()){
System.out.println("--->" + it.next());
}
}

注意,泛型通配符只是一个标识,并不是一种类型,所以没办法像第一种那样能获得 T t对象。

第一种的泛型方法,它明确了是一种类型,只是这种类型暂时还不知道罢了。

(5)泛型限定:

public static void show(Collection<? extends Person> c){

//限定泛型的类型为Person或者为Person的子类

}

public static void show(Collection<? super Person> c){

//限定泛型的类型为Person或者为Person的父类

}


12、Map:存储的是键值对

(1)

Map<Integer,String> map = new HashMap<Integer, String>();

System.out.println(map.put(2,"hello"));  //结果是null

System.out.println(map.put(2,"world")); //结果是hello

System.out.println(map.get(2));  //结果是world

System.out.println(map.containsKey(1)); //false,判断是否包含这样的键

map.remove(2); //删除

Collection<String> coll = map.values(); //把map中所有的值放到Collection里


(2)keySet()的使用,当该map的键我们都不知道的时候,怎么取出里面的键和值呢?

Map<Integer,String> map = new HashMap<Integer, String>();

map.put(1,"hello");

map.put(3,"nihao");

map.put(2,"world");

Set<Integer> set = map.keySet(); //获得键的集合

Iterator<Integer> it = set.iterator();

while(it.hasNext()){

int i = it.next(); //获得键

String value = map.get(i); //获得值

}


(3)entrySet的使用,也是为了获取键和值的。

Map<String,String> map = new HashMap<String,String>();
map.put("1","hello");
map.put("2","world");
map.put("3","zhang");
Set<Map.Entry<String,String>> s = map.entrySet(); //把map里所有键值对的关系对象放到Set里面
Iterator<Map.Entry<String,String>> it = new s.iterator();
while(it.hasNext()){
Map.Entry<String,String> me = it.next(); //获得键值对的关系对象
me.getKey();   //获得键
me.getValue(); //获得值
}

//注意,上面的泛型Map.Entry<String,String> 比较特殊,它就是键值对的关系类型。这种写法其实就是在Map

//接口里面,有一个内部的接口Entry,并且Entry是静态的,所以能直接调用。


(4)HashMap和TreeMap

HashMap:和HashSet类似的数据结构,是不同步的,而且允许键值对为null

TreeMap:和TreeSet类似的数据结构,是不同步的,会对键进行排序。

不同步是为了提高效率,同步是为了提高安全性。


13、工具类:

Arrays:asList,把数组转为List

toString,把数组转为字符串

binarySearch,二分法查找

copyOf,数组复制

fill,数组内容填充,比如数组是1,2,3,4 填充成9,9,9,9

sort,数组排序,从小到大


Collections:集合工具类

List<String> list = new ArrayList<String>();
list.add("hellooo");
list.add("world");
list.add("cba");
list.add("nbab");

(1)排序,

//对List进行从小到大的排序
//结果是cba hellooo nbab world
Collections.sort(list);


(2)自定义排序,下面例子是比较字符串的长度。

public class MyCompare implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}

//对List进行自定义的排序,自定义的方式是实现Comparator重写compare方法
//结果是cba nbab world hellooo
//注意,Comparable和Comparator接口的区别:
//Comparable是内部的,是对List里面的对象进行操作的,比如TreeSet的排序
//Comparator是外部的,是对list整体进行操作的。现在就是对list整体进行操作
Collections.sort(list, new MyCompare());


(3)随机排序

Collections.shuffle(list);


(4)二分法查找,前提是该List必须是升序排列好的

Collections.sort(list);

Collections.binarySearch(list, "world"); //返回找到的位置。

还有另外一种,是自定义排序的。还是用上面的比较器

Collections.sort(list, new Compare());

Collections.binarySearch(list, "world", new Compare());


(5)获取最大值

Collections.max(list); //默认会按Collections.sort(list);排序获取最大值

Collections.max(list, new MyCompare()); //会用自定义的排序获取最大值


(6)反转

Collections.reverse(list);


(7)能将不同步的ArrayList,HashMap等转为同步的,解决多线程并发问题。

Collections.synchronizedList(list);

Collections.synchronizedMap

Collections.synchronizedSet


14、JDK1.5之后的新特性

(1)可变参数,arr实际上是一个数组。

public static int add(int x, int... arr){

int temp = 0;

for(int i=0; i<arr.length; i++){
temp += arr[i];
}
return temp;

}

main:

add(1,2,3); //结果是5,因为x=1

add(5,2,3,9); //结果是14,因为x=5

//注意一点,可变参数只能是参数列表的最后一项,如果int... arr 和 int x调转就报错了。

(2)增强型for循环,把list的每一个元素取出来,赋值给s

for(String s : list){

System.out.println(s);

}

//增强for循环的弊端,只能遍历Collection或数组。

(3)静态导入包

main:

Collections.sort(list); //sort和max都是静态的方法,此时就可以省略写法。

Collections.max(list);


import static java.util.Collections.*; //静态导入包

main:

sort(list); //简写成这样,但是开发中不建议使用,阅读性很差。

max(list);


15、开发常用的工具API

System类

(1)

获取系统当前时间,long time = System.currentTimeMillis();

这个time是当前时间与1970年1月1日0时0分0秒相隔的毫秒数

(2)

获取系统属性,比如获取系统的名称String osName = System.getProperty("os.name");

不同的系统都能实现分行

System.out.println("hello" + System.getProperty("line.separator"); + "world");

(3)

退出程序,System.exit(0); //正常退出,非0是异常退出

(4)

请求系统进行垃圾回收,System.gc();


Math类

double value1 = Math.abs(-5.2); //获取绝对值
System.out.println(value1);  //结果是 5.2

double value2 = Math.ceil(7.2); //获取大于该值的最小整数
System.out.println(value2);  //结果是 8.0

double value3 = Math.floor(7.2); //获取小于该值的最大整数
System.out.println(value3);  //结果是 7.0

double value4 = Math.round(3.45); //四舍五入
System.out.println(value4);  //结果是 3.0

double value5 = Math.pow(2,4); //二的四次方
System.out.println(value5);  //结果是 16.0

double value6 = Math.sin(30*Math.PI/180); //参数是弧度,不能是角度
System.out.println(value6);  //结果是 0.49999999999999994


double value7 = Math.random(); //伪随机数,范围0.0-1.0之间
System.out.println(value7);  //结果不确定


Random r = new Random();
r.nextInt(10); //包含0,不包含10


Date类

//毫秒值转为日期对象。空的构造函数默认是系统当前的时间
Date date = new Date(1396837370954l);
System.out.println(date);

//日期对象转为毫秒值
System.out.println(date.getTime());


DateFormat类

//日期时间格式化,把日期时间对象转为字符串

/**
* (1)系统自带的风格
*/
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String result1 = df.format(new Date());
System.out.println(result1); //
2014年4月7日 上午11时49分02秒

df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
String result2 = df.format(new Date());
System.out.println(result2); //
2014年4月7日 星期一 上午11时50分16秒 CST

df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
String result3 = df.format(new Date());
System.out.println(result3); //
2014-4-7 11:51:09

df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
String result4 = df.format(new Date());
System.out.println(result4); //
14-4-7 上午11:51


/**
* (2)自定义风格
*/
Date date = new Date(1396848370954l);
SimpleDateFormat format = new SimpleDateFormat("yyyy
/MM/dd HH:mm:ss");
String result = format.format(date);
System.out.println(result);
   //2014/04/07 13:26:10


//日期时间解析,把字符串转成日期对象

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = null;
try {
d = format.parse("2014-04-07 10:20:30");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(d);
 // Mon Apr 07 10:20:30 CST 2014

//解析这里有一点值得注意的是,解析的格式必须和format的格式一致。


Calendar类

Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
System.out.println(year + "..." + month); //2014...4
c.set(2013, 3, 8);        //设置时间
c.add(Calendar.MONTH, 2); //修改时间
System.out.println(c.get(Calendar.MONTH)); //5

0 0
原创粉丝点击