第一个java程序
public class HelloWorld {
//所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
public static void main(String[] args) { //这里可通过 java 类名 hello world ! 传入参数
System.out.println("Hello World");
}
}
String args[] 与 String[] args 都可以执行,但推荐使用 String[] args,这样可以避免歧义和误读。前一种主要是为了和C++对齐
两个S是都是大写 System 和String syso快捷
一个文件中可有多个类 但是文件名应该和public声明的类保持一致
javac HelloWorld.java
//如果遇到编码问题,我们可以使用 -encoding 选项设置 utf-8 来编译:
//javac -encoding UTF-8 HelloWorld.java
java HelloWorld
环境配置—网上更详细
x64 Compressed Archive 是压缩包 一般安
classPath的作用是使用java 类名运行java程序时,搜索这个类的路径(class文件的存放搜索地址 ),jdk1.4之后可默认在当前文件夹下搜索,所以之后的版本都不需要指定classpath了
Path则是告诉java这个命令的位置
javac -d的意思是,按照package的文件夹排列 生成对应的class文件,所以,其实并不需要将java源文件按照package的顺序去放,但是为了方便 还是----
如果使用package打包 那么运行java文件的时候 就要用 java 包名.类(因为打包的时候会在当前目录自动生成文件夹)
命名规范
- 所有的标识符都应该以英文字母,美元符( ) 、 或 者 下 划 线 ( ) 开 始 , 注 : )、或者下划线(_)开始,注: )、或者下划线()开始,注:an是合法的
- 包名 小写字母
- 类名:首字母大写,例如 MyFirstJavaClass 。
- 方法名 首字母小写驼峰式
- 普通变量 都小写,连字符连接吧
- 常量 纯大写
- 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。
变量种类
类变量(静态变量)声明在类中,方法体之外,但必须声明为 static 类型。
成员变量(非静态变量)属于对象而不属于类
局部变量
Java 枚举
Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的 bug。
例如,我们为果汁店设计一个程序,它将限制果汁为小杯、中杯、大杯。这就意味着它不允许顾客点除了这三种尺寸外的果汁。
实例
class FreshJuice {
enum FreshJuiceSize{ SMALL, MEDIUM , LARGE }
FreshJuiceSize size;
}
public class FreshJuiceTest {
public static void main(String[] args){
FreshJuice juice = new FreshJuice();
juice.size = FreshJuice.FreshJuiceSize.MEDIUM ;
}
}
数据类型
基本数据类型
除了Sring是大写,且是引用类型;
注:char是单引号,String是双引号
运算
0/0是NaN
1/0是Infinity
-1/0是-Infinity
equal和==
equal判断值是否相等,==判断引用是否相同(引用类型时)
取值范围
对于数值类型的基本类型的取值范围,我们无需强制去记忆,因为它们的值都已经以常量的形式定义在对应的包装类中了。请看下面的例子:
System.out.println(“基本类型:byte 二进制位数:” + Byte.SIZE);
System.out.println(“包装类:java.lang.Byte”);
System.out.println(“最小值:Byte.MIN_VALUE=” + Byte.MIN_VALUE);
System.out.println(“最大值:Byte.MAX_VALUE=” + Byte.MAX_VALUE);
System.out.println();
注 此处开头是大写
默认值
只列出比较特殊的
char ‘u0000’
String (or 任何对象) null
boolean false
需要注意的是局部变量没有默认值,必须指定。编程时候都指定值即可
可使用下划线分割大数字防止看花眼
如1000_1000;3.14_15_926
引用类型
对象、数组都是引用数据类型。
所有引用类型的默认值都是null。
一个引用变量可以用来引用任何与之兼容的类型。
例子:Site site = new Site(“Runoob”)。
自动类型转化
整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。
转换从低级到高级。char(或者byte->short)->int->long->float->double
注意事项
- 不能对boolean类型进行类型转换
- 不同类型的可转化,char可自动类型转换为int(通过ascii码表的值 而非本来的值)
- 不能把对象类型转换成不相关类的对象。
- 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
- 转换过程中可能导致溢出或损失精度
- 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入
隐含强制类型转换
1、 整数的默认类型是 int。定义long时需要后面加L或l,通常建议大写防止和数字1混淆。
- 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。
表达式类型的自动提升–经典错误
short a=5;
a = a-2;//错误 因为2默认是int 会提升会int 赋给short类型
当两个int类型相除,赋给int类型时候,是直接取整而非四舍五入
自动装箱,拆箱
比如当用到数字长度等属性时,需要对象类。如toStrng等方法
Integer x = 5;
String本身就是一个对象
char和Character 不是简单的大写首字母
String类----比较特殊 单独拆出来
String本身就是一个对象
两种创建方式区别
String str = "Runoob";
String str2=new String("Runoob");
String s1 = "Runoob"; // String 直接创建
String s2 = "Runoob"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Runoob"); // String 对象创建
String s5 = new String("Runoob"); // String 对象创建
注意:String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了。如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。
+连接字符串
length()输出长度
格式化字符串
System.out.printf("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
"is %s", floatVar, intVar, stringVar);
你也可以这样写
String fs;
fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);
Java StringBuffer 和 StringBuilder 类
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
可自动扩容
转义字符
Java语言支持一些特殊的转义字符序列。
符号 字符含义
\n 换行 (0x0a)
\r 回车 (0x0d)
\f 换页符(0x0c)
\b 退格 (0x08)
\0 空字符 (0x0)
\s 空格 (0x20)
\t 制表符
" 双引号
’ 单引号
\ 反斜杠
\ddd 八进制字符 (ddd)
\uxxxx 16进制Unicode字符 (xxxx)
java修饰符----一般关注private和public即可
分类
访问修饰符
非访问修饰符
默认访问修饰符
变量和方法:default
接口-变量都隐式声明为 public static final,
接口-方法默认情况下访问权限为 public。
访问控制和继承
请注意以下方法继承的规则:
- 父类中声明为 public 的方法在子类中也必须为 public。
- 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
- 父类中声明为 private 的方法,不能够被子类继承。
增强型for循环–foreach
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ){
System.out.print( x );
}
Java Math 类
Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。
Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。
数组
若需要长度可变的结构,使用Vector
数组作为函数的返回值
public static int[] reverse(int[] list) {
int[] result = new int[list.length];
for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
result[j] = list[i];
}
return result;
}
多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组,例如:
int[][] str = new int[3][4];
但是,java的二维数组其实是一维数组,str[1]中存的其实是一个引用地址,而非int的值本身
不能把java扩充为三维数组 四维度 像其他语言那样,因为已经制定了a【0】的数组元素为int,如果需要这样做,请将其指定为Object类型
length不加括号,是数组的属性
日期时间类
https://www.runoob.com/java/java-date-time.html
java方法
System.out.println()
println() 是一个方法。
System 是系统类。
out 是标准输出对象。
这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()。
可变参数
JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法。
方法的可变参数的声明如下所示:
typeName… parameterName
在方法声明中,在指定参数类型后加一个省略号(…) 。
finalize() 方法
Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。
例如,你可以使用 finalize() 来确保一个对象打开的文件被关闭了。
方法的参数(形参)传递
方法的参数传递为值传递
1、当参数是普通类型时–易理解
如void add(int a){a=a+1}而没有return输出时,仅仅是函数里面的a变了 外面的a是不变的。
2、当参数是引用类型时,分两种情况
2.1、当试图更改引用的地址,如string类型 s1= s1+“aaa”;函数内部的s1会指向一个新的地址(String的特性),函数外面的s1不变(不可见)
2.2、当不改变引用,改变的是引用的数据 如StringBuffer类型 s2 = s2.append(“bbb”) 则对外部是可见的,外面的s2也会变
java面向对象–独立出来 见另一个blog
垃圾回收
垃圾回收只能回收内存资源,对其他物理资源,如数据库连接、磁盘io等无能为力
为了更快使用垃圾回收机制,可以将对象的引用变量设置为null,暗示垃圾回收机制回收对象
可使用runtime对象的gc方法建议回收垃圾,不过用的不多
applet
嵌入浏览器中,可快速运行,大多数浏览器支持这种写法,但是其实必须要用java图形化 ,放弃吧
图形化gui
awt和swing已经被javafx替代了,但是资料比较少。尽量还是别用java开发图形化界面吧
可用金山,WTL,QT,MFC(自绘),WPF等
输入输出
输出的S是大写
输入:
import java.util*;
xxx
Scanner reader = new Scanner(System.in);//输入并不在此处 只是申明
syso("Enter your name:");
String name = reader.next();//此时用户的输入会按回车后被输入到这里 next方法读取一整行的字符
int age=reader.nextInt();//读入一个整数数据
others
jphp可将php编译为java
java使用unicode字符集
break和continue可带标号
方法的参数传递(其实就是引用传参和值传参)
public class FunctionArgs{
public static void main(String[] args){
String a = new String("java");
StringBuffer b = new StringBuffer("java");
changeS(a,b);
System.out.println(a);//java
System.out.println(b);//javachange
}
//若只想写示例程序,声明为static可减少代码量
public static void changeS(String a ,StringBuffer b){
a +="change";
b.append("change");
}
}
java常用的包
java.lang 基本语言类 自动引入
java.io 输入输出
java.util 数据类型类
java.net 网络功能类
其他
形参可变的写法 ,如 public void test(int a ,String…books)
java 局部代码块,即用{}包裹起来的 里面定义的变量 在括号外不可见,这个其实叫初始化快,会比构造器更早运行
好处1:如有多个构造器,就要在多个地方加上初始化函数完成初始化工作,而如果放到初始化块中的话则只要写一次即可(如判断是否登录?);
public class Car
{
private void init()
{
System.out.println("Start engine before run()");
}
//使用初始化块
{
init();
}
public Car()
{
//init();
System.out.println("Run normally");
}
public Car(float velocity)
{
//init();
System.out.println("Run with "+velocity+" miles/h");
}
public static void main(String[]args)
{
new Car();
new Car(210f);
}
}
好处2:但是,如果只是这一点便利的话,还不足以使用初始化块,其实初始化块真正体现其独一无二的作用是在匿名内部类中,由于是匿名内部类,因而无法写构造方法,但是很多时候还是要完成相应的初始化工作,这时就需要用到初始化块了,特别是Android中大量地使用匿名内部类,初始化块的作用就十分突出
静态初始化快,static{} 会在类首次加载的时候运行,所以比在创建对象时候运行的普通初始化快更早运行
java自动装箱
java整个语言都是面向对象的,除了int这些基本类型,方便其他语言的程序员使用。所以它们是大写。String本身就是对象 所以大写
为了贯彻一切都是对象,提供了对应的包装类,可自动拆箱等
Integer a=5;//自动装箱,把基本类型赋给包装类
int b = a;//自动拆箱
除此之外,包装类还可实现基本类型变量和字符串的相互转化。
String a = "123"
int a1 = Integer.parseInt(a);//法1
int a2 = new Integer(a);//法2
String str = String.valueOf(true)//String类特殊 用这个
String str1 = 5+”“;//string还可这样把数值类型转化过来
注意:当使用包装类时,判断两个值相同的包装类,用==会判断false,equals是true;如果大小判断可以用静态的compare方法,如Integer.compare(a,b)
但是一个包装类和一个基本类型是可以相互比较的
String类重写了equal
ps:instanceof 父类也会返回true 所以,重写equal方法要用到反射的getClass方法
java对象打印
通过重写toString方法,里面return出对象的自我描述,就可以通过syso打印出来自定义的描述
IO
IO流分类
1输入流与输出流
首先定义输入和输出,输入输出都是从内存的角度来说的。
输入是指从其他地方到内存,输出是指从内存到其他地方,如硬盘。
2、字节流和字符流
字节流的处理对象是8位的字节,而字符流的处理对象是16位的字符。
字符流的实质也是字节流,但是为了处理的方便……。能用记事本打开的东西都是字符流!
3、节点流与处理流
节点流较低级,是想一个特定的设备读取的流。
而处理流较高级,也被成为包装流,比如和数据库连接,处理流是统一的,而具体的节点流可能流向Mysql、oracle数据库。有点像jvm,无需针对每个操作系统编写java代码
注:名字有file的一般是节点流,有print的一般是处理流
具体介绍
输入流:InputStream(字节流)和Reader(字符流)
输出流:OutputStream和Writer
上面四个类是所有输入输出流的基类,是抽象类,不可直接实例化。
分别有read 和 write方法
使用示例
FileInputStream fis = new FileInputStream("xxx.java")
byte[] bbuf = new byte[1024];//竹筒
int hasRead = 0;//记录读取的字节数
while((hasRead = fis.read(bbuf))>0){
Syso(new String(bbuf,0,hasRead))
}
fis.close();//用完必须关闭
可用try语句的括号语法 保证输出流一定被关闭,需要catch IoException!
注:关闭输出流的时候,会自动调用flash()和close()方法,其中flush会将输出流缓冲区中的数据flush到物理节点,所有用的时候要注意正常使用,一般正常使用即可保证程序正常。
处理流的用法
FileInputStream fis = new FileInputStream("xxx.java")
PrintStream ps = new PrintStream(fos);
//识别处理流很简单,只要构造器c桉树不是具体的物理节点就行,甚至字符串也是物理节点
转换流
java只提供字节流像字符流的转换,因为正常不会反过来转换,用法,如读取键盘输入system.in,普通的Reader读取输入内容的时候依然不太方便,可以将普通的Reader包装成BufferdReader,利用readLine方法可以一次读取一行数据
InputStreamReader reader = new ……(system.in);//将键盘输入转换为Reader对象
BufferedReader = new ^(reader); 然后就能用readLine方法了
File类
file类能新建删除 重命名文件和目录 但是不能访问文件内容本身!需要使用输入 输出流。
Windows路径分隔符为\ ,由于转义字符,要用两条反斜线,或者直接使用斜线/
重定向
java标准输入输出 System.in 和 System.out 正常情况下代表键盘和屏幕
如果要改变 可以用重定向方法 如 setIn、setOut
RA
RandomAccessFile和普通的输入输出流不同的是,它可以直接跳到文件的任意地方来独写数据。
注,RAM是内存 应该翻译成任意访问 而非随机访问!翻译的问题导致难以理解。
对象序列化—详细的以后再看
类实现了Serializable接口,则可序列号,可通过网络、磁盘传输。
文件锁
可加锁防止脏读等冲突问题
NIO(new IO)-----以后再找李刚的书看
jdk1.4开始提供了一种新的方式,采用内存映射的方式处理输入输出,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样访问文件了,比之前快了很多。
JAVA7 改进了nio 称为NIO2
其他
Scanner也可获取键盘输入
缓冲流类似cache 当缓存满了后一次性从缓存中输出或输入
Java基础类库
Runtime类代表JAVA程序运行时的环境
StringBuider类和StringBuffer类基本相同,不同的是前者没有线程安全,所以性能略高,一般情况优先考虑buider
Random类用于生成随机数
时间有DATE和calendar,后者更先进 但是略难用 前者设计不好。JAVA8 又新增了一个java.time的包
java可使用国际化 针对不同语言进行编译
java还有日期格式化等东西
Java集合
为什么需要集合?传统的java数组,由于有固定的长度,无法动态拓展,且无法报错具有映射关系的数组(关联数组),所以需要集合
分类
List:有序可重复
Set:无序不可重复
Quene:队列
Map:关联数组
其中前三种由Collection接口派生而出,后者由Map接口派生而出
Collection接口与Iterator(迭代器,用于迭代Collection,是Collection的父接口)接口
常用方法
add:如果参数是基本类型 能够自动装箱为对象
addAll
clear 清除集合所有元素,将集合长度变为0
contains 返回集合中是否包含指定元素
containsAll 集合里是否包含指定集合里的所有元素
isEmpty
iterator 返回一个迭代器对象,用于遍历集合中的元素
remove
size
toArray
Lambda表达式遍历集合—foreach
Java8 为Interable新增了一个forEach(Consumer action)的默认方法(默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法) ,Consumer是函数式接口,所以能够使用lambda表达式。
for(int x : numbers ){}//数组的叫 for-each,其实也可用来遍历集合,比如int改成Object即可
books.forEach(obj->Syso(obj));//这样可遍历元素输出
Iterator遍历集合元素
// 创建集合
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Zhihu");
// 1\获取迭代器
Iterator<String> it = sites.iterator();
// 输出集合中的所有元素
while(it.hasNext()) {
System.out.println(it.next());
}
Iterator it = books.iterator();
it.forEachRemaining(obj->Syso(obj));//这样可遍历元素输出
Iterator有四个方法
hasNext
next
remove,删除集合里上次next方法返回的元素
forEachRemaining 可使用lambda表达式遍历集合元素
注意:迭代的时候,除了用remove,不能用其他方法修改集合,否则会抛出运行时异常。
Set
HashSet:根据hash算法算出set的位置,速度很快。不保证顺序、不同步,多个线程修改HashSet需要通过代码保证同步、集合元素值可以为null;
LinkedHashSet:多使用一个链表来维护元素的插入顺序,因此性能略低于HashSet
TreeSet:是SortedSet的子类,保证元素处于排序状态,相比父类多了几个方法,且可采用自然排序和定制排序
EnumSet:
上述几个类都是线程不安全的
List
ArrayList和Vector是List的两个经典实现类,都封装了一个动态的Object【】数组
区别:Vector从JDK1.5就有了,很古老,尽量少用,但是是线程安全的。而前者是线程不安全的。其次,Vector提供了一个Stack子类,用来模拟栈这种数据结构
线性表的使用建议
1、如果要遍历List集合,对于ArrayList、Vector 应该使用使用索引的随机访问方法get来遍历,而LinkedList应该使用迭代器Iterator来遍历
2、如果需要经常插入、删除,建议用链表而非普通顺序表
3、如果多个线程需要访问List,可考虑使用Collections将集合包装成线程安全的集合。
Queue和Deque(双端队列,也可作为栈来使用)
Map–字典、关联数组
set与map的关系很密切,如果把key-value中的value当成key的附庸,那么就可以像对待set一样对待Map了。而实际上,java源码是先实现了Map,然后通过包装一个所有value都为null的Map实现了Set集合
常用子类
HashMap —类似ArrayList 线程不安全。优先被推荐使用
HashTable —类似Vector 古老但线程安全。但是即使要创建线程安全的Map实现类,也无需使用这个,而可以通过后面介绍的Collections工具类把HashMap变成线程安全的
LinkedHashMap,维护一个双向链表 保证插入次序
SortedMao 红黑树结构 分自然排序和定制排序
TreeMap
EnumMap
常用方法:
clear 删除该Map对象的所有key-value对
containsKey
containsValue
enterSet 返回Map中包含的所有key-value对所组成的set集合
get
isEmpty
keySet 返回该Map中所有key组成的Set集合
put(key,value)
putAll(Map map)
remove
values 返回所有value组成的collection
Hash的原理
可以指定创建的初始化容量、负载因子,当达到负载极限的时候,会自动增加桶的数量,然后做reHashing
操作集合的工具类-Collections (和之前的区别是多了一个s)
Collections.sort(nums);//nums是一个list集合
可使用synchronizedXXX()方法包装集合类成为线程安全的,比如
List list = Collections.synchronizedList(new ArrayList);
泛型
Java集合的缺点,一旦把一个对象丢进集合里之后,集合就会忘记这个对象的数据类型,当再次取出的时候,编译类型就会变成Object(其运行类型没有改变),当使用的时候,需要做强制类型转换(遍历的时候 要强制转换),这种类型转换会使得代码臃肿,而且容易引发ClassCastException异常(比如把整形误加入了集合,但是在遍历的时候用了String的length方法)。增加了泛型后的集合,可以记住元素的类型,而且在编译的时候检查集合中元素的类型,如果添加不满足要求的对象,编译器会提示错误。
List<String> strList = new ArrayList<String>();//java 7之前 必须这么写
List<String> strList = new ArrayList<>();//java 7以及之后 可以这么写了
Map<String,Integer> = new Hash<>();
事实上,泛型不光可以用于集合,还能用于定义泛型接口、类
public interface List<E>
{
//定义方法的时候 能用E
void add(E x){
}
//还可指定返回值类型
Iterator<E> iterator(){
}
}
所以,可以吧List想象成 E被全部替换成String的特殊List子类接口,等同于下面的类
Public interface ListString extends List{
void add(String x)
Iterator<String> iterator();
}
这样就通过只定义一个接口,实际使用可能无数个接口的问题。而且泛型不光能用于集合类。需要指出的是,定义构造器依然使用 public className()的形式而非public className<>()
泛型的其他知识不深入了 用到的时候看李刚
注解Annotation
@Override 强制子类必须覆盖父类方法。主要是帮程序员避免一些低级错误,比如把info方法不小心写成了inf0,如果这样 在编译运行的时候 都不会给出提示,但是结果和预期不一致,这种没有任何错误提示的错误才是最难调试的错误
@Deprecated 标记已经过时,当其他程序使用过时的类 方法时候给出警告提示
@SuppressWarnings 抑制编译器警告
@FunctionalInterface 函数式接口
还有几个修饰其他Annotation的元Annotation,如@Documented用于javadoc生成文档的不展开了 用到看书,以及还可以自定义注解
多线程
作用:如浏览器同时下载多个图片、一个web服务器同时响应多个用户的请求,java虚拟机提供一个超级线程来进行垃圾回收;图形化界面提供一个进程用于收集用户界面事件
线程必须依赖父进程的存在,线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但是不拥有系统资源
线程是独立运行的,并不知道进程中是否有其他线程的存在,其执行时抢占式的。
java创建了一个进程,实际上有两个进程,一个是java主线程,另一个才是你新建的线程
线程的三种创建方式
1、通过继承Thread类,重写run方法。然后新建子类的对象,调用start方法运行.
2、通过实现Runnable接口,重写run方法。然后新建实现的对象,调用start方法运行.
3、Java5新增,使用Callable和Future创建进程,我们想要把任意方法都包装成线程执行体,而不想每次都写run方法,所以可使用call方法
当使用继承创建对象的时候,多个进程无法共享线程类的实例变量。默认情况主线程为Main,用户启动的线程为Thread-x;
线程常用的方法
Thread.currentThread() 静态方法,返回当前正在执行的线程。如果是继承的方法 可以直接用this访问当前线程
getName 实例方法,返回调用改方法的线程的名字
线程状态
新建New-就绪Runable、运行Running、阻塞Bkocked、死亡Dead
当我们使用start方法启动的时候,线程会就绪等待执行。而我们如果直接调用run方法,那么它立刻就会被运行,而且run方法返回之前,其他线程无法并发执行!
当发生以下情况的时候会blocked状态
1、调用sleep
2、调用了阻塞io方法,返回之前该进程会被阻塞
3、尝试获得一个同步监视器,但是这个同步监视器正被其他线程所持有
4、线程在等待某个通知
5、程序调用了suspend方法挂起,但是这个容易导致死锁。当调用了resume方法恢复时候变成就绪
被阻塞的进程将在合适的时候重新变成就绪状态(而非直接执行状态)
join方法可以让一个进程等待另一个进程完成再运行
后台进程 Daemon Thread 又被称为守护进程或者精灵线程。当所有前台进程死亡的时候,后台线程会自动死亡。Jvm的垃圾回收就是典型的后台线程
yield 线程让步,线程暂停一下 进入就绪状态,让其他优先级更高的进程有机会运行
线程有优先级,可通过setPriority方法 和getPriority方法
线程同步和线程通信、线程池 以后再看