标签: javastringclassthreadexceptionregex
2012-08-18 00:31 2560人阅读 评论(0) 收藏 举报
版权声明:本文为博主原创文章,未经博主允许不得转载。
Java 学习基础知识
一.JAVA 基构架包括:
1. JAVAEE ,企业版,主要用于企业环境的开发和应用。
2. JAVASE, 标准版,主要用于桌面制作和低端商务以用程序。
3. JAVAME,小型版,主要用于小分产品和嵌入式设备。
4.计算机语言的分类:
低级语言:最底层的0 1指令
汇编语言:提供了比较丰富的计算机指令的集合
高级语言:c / java
5. java的发展:
sun公司于1995年5月23开发出来的。
1996,1997 jdk1.0,1.1版本
2004,9.30 18:00 推出j2se
2009.4.20 被Oracle公司收购。
2010.9 Jdk1.7
java之父 詹姆斯.高斯林,标志:一杯咖啡
6 .java语言体系:
javaSE:主要是桌面应用程序的开发,桌面应应用程序:即需要有安装和窗口的程序如:qq
javaEE:主要应用于WEB应用程序的开发(开发网站)
Web页面应用程序:使用浏览器打开的应用程序。
javaME:主要应用于手机开发
java下载工具:http://www.orcale.com
JDK: Java Developer Kit java开发工具集
JRE: java Runtime Environment java运行环境
bin:主要包含的是开发工具
demo: 主要包含的是java语言的示例
include:主要包含开发所需要的操作系统的一些信息
jre: 主要包含java程序运行需要的类
lib: 主要包含的是java程序编译所需的类
sample:主要包含一些典型的小例子
7. java语言的特点:
1.开源性:open sources
2.跨平台型
3.一次编写到处运行
二,JAVA 环境的设置和程序的安装;
1,JAVA 程序的安装下载地址:(www.sun.com).
2.JAVA 环境的设置:
一般设置情况,path环境变量的设置即可,此设置可以整个用户使用,设置方法,
在我的电脑——》高级——》环境变量——》path ——》变量值的设置,
永久设置:java=_home=d:\jdk1.7\bin
临时设置:
set path=jdk的安装目录。
设置class path 环境变量:
class path 用来指定class文件的路径。
class path=d:\
注意在设置class path环境变量时,如果该路径后没有加分号,系统在寻找该class文件时会在指定目录中寻找,如果指定目录中没有,
系统不会在当前目录中寻找。所以一定要加分号。
环境变量不区分大小写。
如下图:
变量值的设置:即就是路径的设置,(此处自己选择,想设置在C, D , E , F 盘都可以),在设置的过程中一定不要改变原有的设置路径,只需要在最前面加上我们所需要的设置的路径即可(如:设置D盘 D:\Program Files\Java\jdk1.7.0\bin;然后选择确定即可),这事还没有完成,我们要在DOS 窗口查看是否正确,
开始——》运行—》cmd ——》set——》查看是否正确。
dos窗口:
cmd :进入dos窗口
md:创建目录 rd:删除目录
cd:进入指定目录 cd..:退回到上一目录
cd/:退回到跟目录
dir:列出当前目录下的文件和文件夹。
三,Java的组成:
1. 关键字: 不能当标示符使用
例如:
class Demo // 定义一个类,类名为 Demo
{
public static void main(String[] args) // 主函数
{
System.out.println(“hello word”); //输出打印
}
}
注:/*1.在定义一个类的同时必须有主函数。
2.如果类名为一个单词,则首字母必须大写,多个单词,每个单词的首字母必须大写 */
2. 标示符:不能以数字开头,不能是关键字
3. 注释:单行注释 // ,多行注释/* 注释语*/ ,文档注释 /**注释语*/
4. 常量:在程序运行的过程中,数据的值不可改变的称之为常量。
整数常量;
小数常量:
字符常量、;使用' '之间的数据。可以使一个字符,一个中文,
可以是一个空格。可以是转义字符 '\t' ,一个Unicode码值 '\u00054'.
布尔常量;用 false true 表示
字符串常量;使用" "之间的数据称之为字符串常量.
5.进制的转换:
十进制转化为二进制,除以2,反向取余数,直到商为零。
二进制转换成十进制按权位展开即可,即乘以100110(2)= 1*2(5)+1*2(2)+1*2(1)
同理:八进制,十六进制转换成十进制,依次按权位展开。
如:123(8) = 1*8(2)+2*8(1)+3*8(0)
54(16) = 5*16(1)+4*16(0)
十进制转化为八进制,十六进制:除以8,16.反向取余数,直到商为零。 A,常量:程序运行期间值不能发生改变的。
常量主要有,整形(short,int,long),浮点型(float,double),字符型(char),布尔型(ture,false),字符串常量。
\r:表示回车,将当前位置移到本行开头。Window系统中,回车符是有两个字符表示 \r\n 。
\n: 表示换行
\t:制表符
\b: 退格符
\’:表示单引号
\’’:表示双引号
\\:表示单斜杠
B,变量:在内存中有固定的单元,用来存放数据,程序运行期间值发生改变。
6.语句;
6.1基本数据类型:
整型:
byte 代表一个字节 2bit -128--127 -2(7)--2(7)-1
short: 代表两个字节 16bit -2(15)--2(15)-1
int :代表四个字节 32bit -2(31)--2(31)-1
long : 八个字节 64bit -2(63)--2(63)-1
程序默认类型为int类型
字符型:两个字节 16bit
浮点型:
float: 四个字节 32bit
double: 八个字节 64bit
java程序中小数部分默认的为double类型
布尔型:代表四个字节或者一个字节
当是基本boolean型是四个字节
当是基本类型的数组时每一个boolean是一个字节
类型转换:强制类型转换,大类型转换为小类型
自动类型转换:小类型转换为大类型
6.2.java常见运算符:
算术运算符:+ - * / % ++ --
注:取于时的结果主要看第一个数(被除数)。
赋值运算符:= == += -= *= /=
比较运算符:> < >= <= !=
逻辑运算符:& | && || !
位运算符: & | ^ >> << >>>
逻辑移位:即无符号右移
&与&& 的区别,&两边都参与计算,&&如果左边为 flase,则不计算右边
运算符的优先级:
. [ ] () {}
++ , -- ,~,!
*, /, %
+ , -
<< , >>, >>>
==, !=
&
^
|
&&
||
?:
=, *=, /=, %=, +=, -=, <<=, >>=, >>>=, &=, ^= , |=
A. 移位运算符(<< 左移,>> 右移,>>>无符号右移,~异或,^取反)
6.3.比较运算符:< <= > >= != ==
1.比较运算符的结果一定是boolean类型,true 或者false
2.较运算符比较的数据类型要一致,char,byte,short比较时类型会自动提升为int
3.整数和浮点数也可以比较
4.double类型的不可以比较,会损失精度。
6.4.逻辑运算符:用于一连串的比较,结果是true或者false
& 两边的都为true时,结果为true,负责有一边为false结果都为false
&& 短路与,当第一个比较的运算结果为false时,忽略第二个运算的比较
| 两边的比较运算都需要做比较。只要运算的结果又一个为true时,结果为true
|| 短路或,当第一个比较的运算结果为true时,忽略第二个运算的比较
! 仅作一个比较,非真,即为假。非假,即为真。
^(异或) 两边相反时,结果为true,相同时为false
逻辑运算符:主要用于连接多个比较运算符。
结果也是boolean类型 true 或者 false,在为运算运算过程中都是以二进制计算,即0或者1.
6.5. 位运算符:
& | ^
码值:
原码:就是一个数的二进制表现形式。
反码:给每一位取反后的值。
补码:就是在反码的基础上加1(此处的加1是指1的二进制形式,如:一个字节表示:0000 0001)
补码求原码:
1,正数的原码就是补码。
2.负数的原码:给补码在求反一次加1.
注:补码在内存中主要是负数的存储方式。他的最高位为1(1代表符号位),而正数的最高位为0(即符号位)。
总结规律:
当三个数连续进行^ 而且有连个数相同, 那么结果一定等于那个不同的数据。项目中可以利用该规律进行高效的数据交换
例1:
class Demo6
{
public static void main(String[] args)
{
&
操作数1 操作数2 结果 将true = 1 false = 0
1 1 1
1 0 0
0 0 0
0 1 0
练习: 6 & 8
分析:
0000 0110 6
& 0000 1000 8
-------------------
0000 0000 0
0000 0101
& 0000 0111 7
--------------------
0000 0101 5
System.out.println( 6 & 8 );
System.out.println( 5 & 7 );
|
操作数1 操作数2 结果 将true = 1 false = 0
1 1 1
1 0 1
0 0 0
0 1 1
0000 0110 6
| 0000 1000 8
----------------
0000 1110 8+4+2 = 14
System.out.println( 6 | 8 );
System.out.println( 7 | 15 );
~
操作数1 将true = 1 false = 0
1 0
0 1
~ 0000 1000 8
------------
1111 0111 负数 补码
1000 1000 取反
+ 0000 0001 +1
------------
1000 1001 -9
1000 0110 -6的原码
1111 1001 -6的反码
+ 0000 0001 1的原码 也是补码
------------------------------------
1111 1010 -6的补码
1000 0101 -6的补码的反码
+ 0000 0001 1的补码
------------------------------------
1000 0110 -6的原码
总结规律:
正数的~ = 正数+1 并将符号翻转 ~90 = -(90+1) = -91
负数的~ = 负数+1 并将符号翻转 -6 = -(-6+1)= 5
byte a = -6;
System.out.println( ~8 );
~ 1111 1010 -6的补码
-----------
0000 0101 5
System.out.println( ~-6 );
System.out.println( ~-48 );
^
操作数1 操作数2 结果 将true = 1 false = 0
1 1 0
1 0 1
0 0 0
0 1 1
0000 0110 6的原码 补码
^ 0000 0111 7的原码 补码
--------------
0000 0001 原码 1 补码形式
总结规律:
当三个数连续进行^ 而且有连个数相同, 那么结果一定等于那个不同的数据。项目中可以利用该规律进行高效的数据交换。
6.6. 算术移位:
>>
<<
移位:
左移:在左移的过程中数值会增大,如果所要移动的数是2的幂数时,即2(n),2的n次方。
此时使用所要移动的数乘以2(n),即(乘以2的幂数,n代表移动的位数)。如果不是2的幂数,此方法不能使用。
右移:在右移的过程中数值会减小,如果所要移动的数是2的幂数时,即2(n),2的n次方。
此时使用所要移动的数除以2(n),即(除以2的幂数,n代表移动的位数)。如果不是2的幂数,此方法不能使用。
逻辑移位:
>>>
即无符号右移,不管是正数还是负数在移位的过程中最高位都是补零。
交换两个数的方法1:通常是定义第三方变量用于存储数据,然后进行交换。
int x = 45;
int y = 89;
int temp = x;
x = y;
y = temp;
//Method 2: 将x与y装在一个容器中,即y这个比较大的容器
y = y+x; //将x装入y中
x = y-x; //通过x与y之和后的y减去x(即这时y中存储的是x)
y = y-x; //使用x+y之和减去y中存储的x,这是x中只剩下y
//Method 3: 使用取反操作
x = x^y;
y = x^y; // x^y^y = x
x = x^y; // x^y^x = y
}
}
6.7. 优先级:
自增和自减的优先级和()同级
7.JAVA中的流程控制语句:
1.顺序语句:按照一定的顺序执行代码。
2.判断语句:按判断的结果来执行
方式1:
if( 判断条件 ){ 如果条件满足。执行该代码 }
方式2:
if( 判断条件 ){ 如果条件满足。执行该代码 }else{ // 不成立执行该代码 }
方式3:
if( 判断条件1 ){}else if( 判断条件2 ){} else if( 判断条件3 ){}...else{}
备注: 判断条件: boolean 比较元算符 逻辑运算符.
在使用if语句时,如果if的语句后没有写{},此时if语句执行的是离他最近的语句。为了避免代码混乱,最好书写清楚。
例1:
class Sentence
{
public static void main(String[] args)
{
int a = 78;
int b = 65;
if(a > b)
{
System.out.println(a);
}
System.out.println("Hello World!");
}
}
3.选择语句: 按照选择进行执
class Demo3
{
public static void main(String[] args)
{
int month = 34;
switch(month)
{
case 12:
case 1:
case 2:System.out.println("冬季");// break;
case 3:
case 4:
case 5:System.out.println("春季"); break;
case 6:
case 7:
case 8:System.out.println("夏季"); break;
case 9:
case 10:
case 11: System.out.println("秋季"); break;
default:
System.out.println("输入错误,请检查");
}
}
}
实验总结:当输入的选项满足switch语句时,首先执行switch内部的case语句,然后结束整个语句。
当输入的选项不满case语句时,首先先执行case语句,再执行default语句。
如果default语句没有放在最后,而是case语句之前,则需要执行case语句,然后通过break语句或者大口号(})结束整个语句。
关键字:
switch :用于输入用户的选择
case :代表一个选项
break :代表选择结束 switch语句的结束}也可以终止选择
执行原理:
先执行case语句,再执行default语句。
使用switch做选择时必须要注意:
1. 用的选择只能是如下数据类型:
byte 、 short 、 char 、 int 、枚举
注意问题:
判断语句 和 选择语句
if ----> switch 成绩的等级 不是所有的都可转
swicth ----> if 完全可以
实际开发中:
原则:能够使用switch实现的,优先使用switch case语句
优点:
1. 结构比较清晰
2. 效率高,所有的选项内容会提前进入内存
4. 循环语句:按照循环的次数进行重复执行
5.
循环方式1:
while( 循环的条件 )
{
满足条件重复执行
}
方式2: do while
do{
需要重复的代码
}while( 循环的条件 );
总结:
while和do while和相互转换,但是不同的是do while至少要执行一次。
for(条件初始化语句;循环条件;循环后语句)
{
需要执行的代码;
}*/
条件初始化语句:主要用于初始化变量。
循环条件语句 :比较运算符和逻辑运算符。
循环后语句 :使得初始化变量循环一次之后发生变化。
for循环运行原理:
for( 1;2;3 ){
// 4
}
顺序:
1243
243
243
初始化语句永远只是执行一次。
例2;
class ForSentence
{
public static void main(String[] args)
{
for(int x=0;x<9;x++)
{
System.out.println("x="+x);
}
System.out.println(x);
}
}
/*ForSentence.java:21: 错误: 找不到符号
System.out.println(x);
^
符号: 变量 x
位置: 类 ForSentence
1 个错误
总结:1.通过实验可以的知:在for循环语句中定义的局部变量,仅在for语句中有效,当for循环语句执行完毕
,将释存储放空间。如果在循环该语外访问该变量,该变量已经不存在。
例3;
class Demo4
{
public static void main(String[] args)
{
int x=0;
for( ;x<9;)
{
System.out.println("x="+x);
//x++;
}
System.out.println(x);
}
}
结论:1.在for语句中,如果初始化的变量定义在for循环体的外面(即全局变量),此时可以被其他成员访问。
2.for循环语句中的初始化语句可以为空
3.for循环语句中的循环后需要执行的语句可以为空,但是一定要在{}执行代码中写上,
如果没有循环后需要执行的语句,会出现死循环。
4,for语句中的所用语句为空时,此时处于死循环。
循环控制语句: break, continue的用法
break: 主用用于停止循环或着选择语句,
适用范围:循环语句,选择语句。
continue:主要用于控制循环体,是循环继续执行下一次,并不能结束整个循环。
适用于:循环语句
class Demo4
{
public static void main(String[] args)
{
int x=0;
for( ;x<9;)
{
System.out.println("x="+x);
//x++;
}
System.out.println(x);
}
}
结论:1.在for语句中,如果变量定义在for循环的外面,此时可以被其他方法访问。
2.for循环语句中的初始化语句可以为空
3.for循环语句中的循环后需要执行的语句可以为空,但是一定要在{}执行代码中写上,
如果没有循环后需要执行的语句,会出现死循环。
4,for语句中的所用语句为空时,此时处于死循环。
代码块和变量的作用域
代码块:使用{}将相同功能的代码包含起来,那么这个{}内的称之为 代码块。
特点:
1,代码块后面不要使用分号(;),通知编译器结束语句。
2,代码块是按照顺序依次执行。
五:流程控制
顺序结构
选择结构
循环结构
1.if(条件表达式)
语句;
例2. if(条件表达式)
语句1;
else if(条件表达式)
语句2;
else
语句3;
class ifexpression
{
public static void main (String[] args)
{
int val=75;
if(val>90)
System.out.println("优秀");
if(val>70 && val<80)
System.out.println("良好");
if(val<60)
System.out.println("努力");
}
}
例3:switch(常量表达式)
case常量表达式1: 语句1;break;
case常量表达式2: 语句1;break;
case常量表达式3: 语句1;break;
default: 语句n;
六:数组
1. 一位数组的定义方式:
元素类型 [ ] 数组名= new 元素类型[元素个数或数组长度 ];
例:int arr [ ]=new int[ ]{1,2,3,4,5} ;
元素类型 [ ] 数组名={元素 } 例:Int arr[ ]={3,2,4,5} ;
注:/*1.输出打印部分,使用”+”,主要作用是字符窜之间的连接
2. “ “ (双引号)的用法:不发生改变的放在引号中间,改变的放在引号外,并两个字符串之间用”+”连接 */
函数调用方法:
class Demo
{
public static void main(String[] args)
{
int arr[]={3,5,6,2,8};
printArr(arr);
}
public static void printArr(int arr[])
{
for(int i=0;i<arr.length;i++)
System.out.println("i="+i+","+"arr["+i+"]="+arr[i]+";");
}
}
//对一位数组中的元素排序
class NumberDemo
{
public static void main(String[] args)
{
int a[]={20,10,50,40,30,70,60,80,90,100};
sort(a);
sop(a);
}
public static void sort(int arr[])
{
for(int x=0;x<arr.length-1;x++)
{
if(arr[x]>arr[x+1])
{
int temp=arr[x];
arr[x]=arr[x+1];
arr[x+1]=temp;
}
}
}
public static void sop(int a[])
{
for(int i=0;i<a.length;i++)
{
System.out.println("a["+i+"]="+a[i]);
}
}
} */
//练习二:乘法表
class chengFaDemo
{
public static void main(String[] args)
{
chengFa();
}
public static void chengFa()
{
for(int i=1;i<10;i++)
{ for(int j=1;j<=i;j++)
{
sop(i,j);
}
System.out.println();
}
}
public static void sop(int x,int y)
{
System.out.print(x+"*"+y+"="+x*y+"\t");
}
}
例 2:
比较数组中的数字,并找出最大值和最小值
class Demo
{
public static int getmax(int arr[])
{
int max=arr[0];
for(int i=1;i<arr.length;i++)
{ if(arr[i]>max)
max=arr[i];
}
return max;
}
public static int getmin(int arr[])
{
int min=arr[0];
for(int i=1;i<arr.length;i++)
{ if(arr[i]<min)
min=arr[i];
}
return min;
}
public static void main(String[] args)
{
int arr[]={3,5,6,2,8,7};
int max=getmax(arr);
System.out.println("max="+max);
int min=getmin(arr);
System.out.println("min="+min);
}
}
例3;
// 查找数组下标所对应的元素
class ArrTest
{
public static void main(String[] args)
{
int arr[]={3,6,2,8,1};
int index=getIndex(arr,2);
System.out.println("Index="+index);
}
// 获取key第一次出现的数,如果不是返回子为-1 ,则key不在数组中
public static int getIndex(int arr[],int key)
{
for(int i=0;i<arr.length;i++)
{ if(arr[i]==key)
return i;
}
return -1;
}
}
例4:
// 折半查找,可以提高效率,但是比须是有序的的数组
class ArrTest
{
public static void main(String[] args)
{
int arr[]={4,7,8,24,45,67};
int index=halfSearch(arr,3);
System.out.println("Index="+index);
}
public static int halfSearch(int arr[],int key)
{
int min=0,max=arr.length-1,mid;
while(min<max)
{
mid=(max+min)>>1;
if(key>arr[mid])
min=mid+1;
else if(key<arr[mid])
max=mid-1;
else
return mid;
}
return -1;
}
public static int halfSearch(int arr[],int key)
{
int min,max,mid;
min=0;
max=arr.length-1;
mid=(min+max)/2;
while(arr[mid]!=key)
{
if(key>arr[mid])
min=mid+1;
else if(key<arr[mid])
max=mid-1;
if(min>max)
return -1;
mid=(min+max)/2;
}
return mid;
}
}
例5:
//有一个有序的数组,将一个元素插入到数组中,并保证数组还是有序的。
// 折半查找,可以提高效率,但是比粗是有序的的数组
class ArrTest
{
public static void main(String[] args)
{
int arr[]={4,7,8,24,45,67};
int index=halfSearch(arr,3);
System.out.println("Index="+index);
}
public static int halfSearch_2(int arr[],int key)
{
int min=0,max=arr.length-1,mid;
while(min<max)
{
mid=(max+min)>>1;
if(key>arr[mid])
min=mid+1;
else if(key<arr[mid])
max=mid-1;
else
return mid;
}
return min;
}
}
例6:
// 第一种:十进制转换为二进制
class ArrTest
{
public static void main(String[] args)
{
toBin(6)
}
public static void toBin(int num)
{
while(num>0)
{
System.out.println(num%2);
num=num/2;
}
}
}
// 第二种:十进制转换为二进制
class ArrTest
{
public static void main(String[] args)
{
toBin(6);
}
public static void toBin(int num)
{
StringBuffer s = new StringBuffer();
while(num>0)
{
s.append(num%2);
num=num/2;
}
System.out.println(s.reverse());
}
}
第三种:十进制转换为二进制
class ArrTest
{
public static void main(String[] args)
{
toBin(60);
}
public static void toBin(int num)
{
char chs[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char arr[] = new char[8];
int pos=arr.length;
while(num!=0)
{
int temp = num & 1;
arr[--pos] = chs[temp];
num = num>>>1;
}
for(int x=pos;x<arr.length;x++)
{
System.out.println(arr[x]);
}
}
}
2: 十进制转换为十六进制
int n = num & 15;
n1-10+'A';
int temp=num>>>4;
temp&15;
*/
// 第一种:十进制转换为十六进制
class ArrTest
{
public static void main(String[] args)
{
toHex(6);
}
for(int x=0;x<8;x++)
{
int temp=num&15;
if(temp>9)
System.out.println((char)(temp-10+'A'));
else
System.out.println(temp);
num=num>>>4;
}
}
// 第2种:十进制转换为十六进制
class ArrTest
{
public static void main(String[] args)
{
toHex(60);
}
public static void toHex(int num)
{
char chs[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char arr[] = new char[8];
for(int x=0;x<arr.length-1;x++)
{
int temp = num & 15;
// System.out.println(chs[temp]);
arr[x]=chs[temp];
num = num>>>4;
}
for(int x=0;x<arr.length-1;x++)
{
System.out.println(arr[x]+",");
}
}
// 第三种:十进制转换为十六进制
class ArrTest
{
public static void main(String[] args)
{
toHex(60);
}
public static void toHex(int num)
{
char chs[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char arr[] = new char[8];
int pos=arr.length;
while(num!=0)
{
int temp=num&15;
arr[--pos]=chs[temp];
num=num>>>4;
}
for(int x=pos;x<arr.length;x++)
{
System.out.println(arr[x]);
}
}
}
2. 二维数组:
定义方式1:元素类型数组名 [ ][ ]=new 元素类型[数组长度 ] [数组长度];
例: IInt arr[ ] [ ] =new int [2 ][3 ] 相当于两个一维数组
arr[0]=new int[3]; arr[1]=new int[3]
定义方式2:元素类型数组名 [ ][ ]= { 元素};
例:Int arr[ 3][ ]={{1,2,3},{4,5},{7}};
相当于三个一维数组:arr[0]={1,2,3} ; arr[1]={4,5}; arr[2]={7};
注:数组中第二个中括号中不写元素的个数,这样方便操作,因为我们在定义数组的时,数组中的元素如果太多,在定义是困难.
例1:将数组中的元素按大小顺序排列
classCompaer
{
public static void main(String[ ] args)
{
int arr[ 2][ 4]={5,3,2,0,6,8,2,9};
Arrprint(arr);
forXuhuan(arr);
forTo(arr);
Arrprint( arr);
}
}
/* 选择发排序 */
public static void forTo(int arr)
{
for(int i=0;i<arr.length-1;i++)
for(j=1;j<arr.length;j++)
If(arr[i]>arr[y])
{
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
/* 冒泡法排序*/
public static void forXuhuan(int arr)
{
for(int i=0;i<arr.length-1;i++)
for(j=1;j<arr.length-i;j++)
If(arr[j]>arr[j+1])
{
int temp= arr[j];
arr[j]= arr[j+1];
arr[j+1]=temp;
}
}
public static void Arrprint(int arr)
{
for(int x=0;x<arr.length;x++)
{
If(x!=arr.length-1)
System.out.print(arr[x]+”,”);
else
System.out.println(arr[x]);
}
}
5.面向对象:
静态:static。
用法:是一个修饰符,用于修饰成员(成员变量,成员函数).
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,
还可以直接被类名调用。类名.静态成员。
static特点:
1,随着类的加载而加载。
也就说:静态会随着类的消失而消失。说明它的生命周期最长。
2,优先于的对象存在
明确一点:静态是先存在。对象是后存在的。
3,被所有对象所共享
4,可以直接被类名所调用。
实例变量和类变量的区别:
1,存放位置。
类变量随着类的加载而存在于方法区中。
实例变量随着对象的建立而存在于堆内存中。
2,生命周期:
类变量生命周期最长,随着类的消失而消失。
实例变量生命周期随着对象的消失而消失
静态使用注意事项:
1,静态方法只能访问静态成员。
非静态方法既可以访问静态也可以访问非静态。
2,静态方法中不可以定义this,super关键字。
因为静态优先于对象存在。所以静态方法中不可以出现this。
3,主函数是静态的。
静态有利有弊
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。
可以直接被类名调用。
弊端:生命周期过长。
访问出现局限性。(静态虽好,只能访问静态。)
饿汉式:是先初始化对象。
Single类一进内存,就已经创建好了对象。
class Single
{
private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
//对象是方法被调用时,才初始化,也叫做对象的延时加载。成为:懒汉式。
//Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}
//记录原则:定义单例,建议使用饿汉式。
class
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
// 继承:
class Fu extends Object
{
int num=5;
Fu()
{
System.out.println("NAME");
}
Fu(int x)
{
System.out.println("fu ...."+x);
}
}
class Zi extends Fu
{
Zi()
{
System.out.println("zi run");
}
Zi(int x)
{
System.out.println("zi..."+x);
}
}
class Person
{
public static void main(String[] args)
{
Zi z = new Zi(0);
System.out.println(z.num);
}
}
*
当子类继承父类,沿袭了父类的功能,到子类中,
但是子类虽具备该功能,但是功能的内容却和父类不一致,
这时,没有必要定义新功能,而是使用覆盖特殊,保留父类的功能定义,并重写功能内容。
覆盖:override
1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
2,静态只能覆盖静态。
记住大家:
重载:只看同名函数的参数列表。
重写:子父类方法要一模一样。(即函数名和参数列表)
3,子父类中的构造函数。
在对子类对象进行初始化时,父类的构造函数也会运行,
那是因为子类的构造函数默认第一行有一条隐式的语句 super();
super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();
为什么子类一定要访问父类中的构造函数。
因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。
所以子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
注意:super语句一定定义在子类构造函数的第一行。
*
结论:
子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
final : 最终。作为一个修饰符,
1,可以修饰类,函数,变量。
2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。
3,被final修饰的方法不可以被复写。
4,被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,有可以修饰局部变量。
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。
而这个值不需要改变,所以加上final修饰。
5.作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。单词间通过_连接。
6,内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。
class Demo
{
final int x = 3;
public static final double PI = 3.14;
final void show1()
{}
void show2()
{
final int y = 4;
System.out.println(3.14);
}
}
class SubDemo extends Demo
{
//void show1(){}
}
class FinalDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
抽象类的特点:
1,抽象方法一定在抽象类中。
2,抽象方法和抽象类都必须被abstract关键字修饰。
3,抽象类不可以用new创建对象。因为调用抽象方法没意义。
4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。
如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
4.抽象类的出现提高了代码的复用性。让子类继承使用
6.抽象类中一定有构造函数。主要是给成员初始化。
* 优点:
* 1.提高代码的复用性。
* 2.强制子类实现父类中没有实现的功能
抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。
这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。
通过抽象方法来表示。
抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。
抽象类不可以实例化。
特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
abstract 关键字,和哪些关键字不能共存。
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。
而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
可是抽象方法运行没意义。
abstract class Animal
{
String name = "huan huan";
public abstract void run();
public Animal()
{
System.out.println("父类构造函数");
}
}
class Dog extends Animal
{
public void run()
{
System.out.println("dog 跑......");
}
}
public class AbstractClass
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Dog d = new Dog();
d.run();
}
}
接口的特点:
1. 接口中定义的所有的属性默认是public static final的,即静态常量
既然是常量,那么定义的时候必须赋值。
2. 接口中定义的方法不能有方法体。接口中定义的方法默认添加public abstract
3. 有抽象函数的不一定是抽象类,也可以是接口类。
4. 由于接口中的方法默认都是抽象的,所以不能被实例化。
5. 对于接口而言,可以使用子类来实现接口中未被实现的功能函数。
6. 如果实现类中要访问接口中的成员,不能使用super关键字。因为两者之间没有显示的继承关系,
况且接口中的成员成员属性是静态的。可以使用接口名直接访问。*/
接口:是不可以创建对象的,因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。
否则子类是一个抽象类。
接口可以被类多实现,也是对多继承不支持的转换形式。java支持多实现。
interface Inter
{
public static final int NUM = 3;
public abstract void show();
}
interface InterA
{
public abstract void show();
}
class Demo
{
public void function(){}
}
class Test extends Demo implements Inter,InterA
{
public void show(){}
}
为什么定义接口?主要是胡根据现实中事物的存在而定义个一种抽象事物,而该抽象的发法包含一类事物的共性,
此时就需要定义为一个接口,其他类如果需要该接口中的方法时,只能是实现该接口,实现其抽象方法,正在方法的方法体中
写上自己需要的执行代码即可。接口的出现主要是避免了继承的缺陷,在类与类之间只能是单继承关系,而类与接口之间可以多实现,
这样可以扩展类的功能,即增强类的扩展性。
instanceof关键字:该关键字用来判断一个对象是否是指定类的对象或者接口。属于比较运算符
用法:
对象 instanceof 类;
该表达式是一个比较运算符,返回的结果是boolea类型 true|false
多态:
1,多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
2,多态的前提
必须是类与类之间有关系。要么继承,要么实现。
通常还有一个前提:存在覆盖。
3,多态的好处
多态的出现大大的提高程序的扩展性。
4,多态的弊端:
虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员。
5,多态的应用
6,多态的出现代码中的特点(多态使用的注意事项)
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:非静态成员函数在多态调用时,编译看左边,运行看右边。
(简单的理解就是,在编译的时候看那父类中是否有调用的函数,如果没有,编译失败,如果有,编译通过。
运行时看子类中是否有调用的函数,如果没有,会调用父类中的函数)。
在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
在多态中,静态成员函数的特点:
无论编译和运行,都参考做左边。
/*
第一种情况:
class A
{
public static int a = 1;
}
class B
{
public static int b = 2;
}
class C
{
public static int c = 3;
}
//情况2:
*/
class A
{
public static int a = 1 + B.b;
}
class B
{
public static int b = 2 + C.c;
}
class C
{
public static int c = 3 + A.a;
}
/情况3错误
class A extends C
{
public static int a = 1 + c;
}
class B extends A
{
public static int b = 2 + a;
}
class C extends B
{
public static int c = 3 + b;
}
*/
public class Test
{
public static void main(String[] args)
{
// 情况1的输出
//System.out.println( A.a + B.b + C.c );
// 情况2的输出
System.out.println( A.a + B.b + C.c );
// 情况3的输出
//System.out.println( A.a + B.b + C.c );
// 情况4 将以上3中情况的输出类变量的顺序加以任意改变参考结果
}
}
Static Nested Class 和 Inner Class的:
1. 成员内部类(成员属性、成员方法)
1.1 私有的成员内部类
特点:不能在其他类中直接创建内部类对象来访问
1.2 静态的成员内部类
特点:如果内部类中包含有静态成员,那么java规定内部类必须声明为静态的访问静态内部类的形式:
Outer.Inner in = new Outer.Inner();
1.3 匿名内部类
2. 局部内部类
包含在外部类的函数中的内部类称之为局部内部类。
访问:可以在包含局部内部类的方法中直接创建局部内部类的对象调用局部内部类的成员。
访问方式:
1.内部类可以直接访问外部类中的成员
2.外部类要访问内部类需要创建内部类的对象。
3.在外部类的成员位置上建立内部类对象可一直接访问内部类中的成员。
4.从内部类中访问本地变量; 需要被声明为最终类型
class Outer
{
int x = 4;
static class Inner
{
int x = 1;
public static void method()
{
//System.out.println(Outer.this.x);
System.out.println("成员位置内部类、、、");
}
}
public void show()
{
//Inner in = new Inner();
//in.method();
System.out.println("外部类方法");
}
//第二种;
public void InnerMethod()
{
final int x = 4;
class Inner
{
int x = 8;
public void print()
{
int x = 2;
System.out.println("x = " + x);
System.out.println("内部类定义在函数的内部");
}
}
Inner in = new Inner();
in.print();
}
public void out()
{
System.out.println("外部类方法"+x);
}
}
class Demo1
{
public static void main(String[] args)
{
//内部类在成员位置上的非静态访问方式;
/* Outer out = new Outer();
out.show();
Outer.Inner in = new Outer().new Inner();
in.method();
//静态访问方式
Outer.Inner in = new Outer.Inner();
in.method();*/
//第三种:内部类在函数的内部
Outer out = new Outer();
out.InnerMethod();
System.out.println("Hello World!");
}
}
匿名内部类:
1. 当成员内部类和外部的抽象类或接口有继承或者实现关系,那么可以直接使用匿名内部类进行代码的简化
2. 可以在外部类的成员函数中直接创建抽象类或接口的对象,只要在创建对象的同时使用{}重写或实现抽象类的方法或接口的未实现方法即可。
开发中的启示:
1. 任何类都可以new,只不过抽象类接口在new的时候需要使用{}同时实现未被父类实现的方法即可。
interface MyShape
{
int x = 4;
void print();
}
class Outer
{
int x = 9;
public void show()
{
final int x = 8;
new MyShape(){
public void print()
{
System.out.println(Outer.this.show());
System.out.println("匿名内部类的使用");
}
}.print();
}
public void show()
{
System.out.println("外部类方法");
}
class Inner implements MyShape
{
public void print()
{
int x = 3;
System.out.println(x);
System.out.println("内部类可以实现接口的");
}
}
Inner in = new Inner();
in.print(); */
}
class Demo4
{
public static void main(String[] args)
{
Outer out = new Outer();
out.show();
System.out.println("Hello World!");
}
}
/*结论:1.当内部类实现接口时,如果该方法中访问的变量本类没有,则会在父类中查找(接口名.变量名),
如果父类中没有,会出现异常。
2.内部类在继承接口和抽象类的时候,都可以通过new 关键字创建对象(即匿名内部类),
只需要在对象后增加{}如:new person(){//复写父类的方法}; ,并在大口号中将父类中的方法复写.
3.匿名内部类简化了代码的书写,提高效率。*/
异常:Exception
实现方式一:
try{ // 可能发生异常的代码 } catch( 异常类的类型 e ){ // 当发生指定异常的时候的处理代码 }catch...
比较适合用于专门的处理异常的代码,不适合释放资源的代码。
实现方式二:
try{ } catch(){} finally{ // 释放资源的代码 }
finally块是程序在正常情况下或异常情况下都会运行的。
比较适合用于既要处理异常又有资源释放的代码。
实现方式三:
try{ }finally{ // 释放资源 }
比较适合处理的都是运行时异常且有资源释放的代码。
finally:关键字主要用于释放系统资源。
1. 在处理异常的时候该语句块只能有一个。
2. 无论程序正常还是异常,都执行finally。
自定义异常
运行时异常:
SecurityException 安全异常
IllegalArgumentException 无效的参数异常
ClassCastException 类的转型异常
IndexOutOfBoundsException 数组角标越界异常
ArithmeticException 算术异常
EventException
非运行时异常:
ClassNotFoundException 找不到类异常
FileNotFoundException 文件找不到异常
IOException 流异常
Error:
OutOfMemoryError 内存溢出错误
注意:1.在导包的过程import 一定不能放在package之上。否则编译报错。
2.一个类中可以导入多个包,导包方法:包名.类名,也可以使用:包名.*,
这虽然简化了代码的书写,但是如果一个包中有多个类的时候,这样会导致导入的其他没有使用到类,
浪费内存空间。建议使用,需要那个就导入那个类。
3.在编译的过程中使用方法:javac <options> <source files> 即:javac -d 目录存放位置 源文件
运行时:java 包名.类名
通过包所在的路径访问包中的类:一般包放在哪我们就需要设置( set classpath)在这个路径下调用包中类的方法。
jar工具:主要用于对class文件进行打包(压缩)
jar工具压缩的文件后缀一定是: .jar( java active rar ) war( web active rar )
jar用法:
jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
示例 1:将两个类文件归档到一个名为 classes.jar 的归档文件中:
jar cvf classes.jar Foo.class Bar.class 压缩
示例 2:使用现有的清单文件 "mymanifest" 并将 foo/ 目录中的所有文件归档到 "classes.jar" 中:
jar cvfm classes.jar mymanifest -C foo/ .
jar的常见应用:
压缩: jar -cvf jar文件 要压缩的文件
查看压缩信息 jar -tvf jar文件 [ > 重定向文件 ]
解压: jar -xvf jar文件
进程:是一个正在执行中的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。
线程在控制着进程的执行。
一个进程中至少有一个线程。
Java VM 启动的时候会有一个进程java.exe.
该进程中至少一个线程负责java程序的执行。
而且这个线程运行的代码存在于main方法中。
该线程称之为主线程。
扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。
1,如何在自定义的代码中,自定义一个线程呢?
通过对api的查找,java已经提供了对线程这类事物的描述。就Thread类。
创建线程的第一种方式:继承Thread类。
步骤:
1,定义类继承Thread。
2,复写Thread类中的run方法。
目的:将自定义代码存储在run方法。让线程运行。
3,调用线程的start方法,
该方法两个作用:启动线程,调用run方法。
发现运行结果每一次都不同。
因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。
明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。
我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。
这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。
为什么要覆盖run方法呢?
Thread类用于描述线程。
该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
也就是说Thread类中的run方法,用于存储线程要运行的代码。
class Demo extends Thread
{
public void run()
{
for(int x=0; x<60; x++)
System.out.println("demo run----"+x);
}
}
class ThreadDemo
{
public static void main(String[] args)
{
//for(int x=0; x<4000; x++)
//System.out.println("Hello World!");
Demo d = new Demo();//创建好一个线程。
//d.start();//开启线程并执行该线程的run方法。
d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。
for(int x=0; x<60; x++)
System.out.println("Hello World!--"+x);
}
}
什么是线程:线程是一个应用程序执行时候的多条路径。
java中的线程:
Thread :线程
java.lang.*
实现:
创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。
该子类应重写 Thread 类的 run 方法。
线程执行的原理:
CPU + 代码 + 数据
thread1 main 进行抢占CPU资源
在物理上只有一个CPU的情况下,JVM是采用抢占CPU资源,给不同的线程划分指定执行时间片的方式来实现。
java中隐含的两个线程:
1. main函数 JVM main函数也称之为主线程
2. GC 是一个后台的线程( 自动升级 )
java中定义线程的模型:
1. CPU
2. 功能代码
3. 数据
线程的使用细节:
1. 线程的启动使用父类的start()方法
2. 如果线程对象直接调用run(),那么JVN不会当作线程来运行,会认为是普通的方法调用
3. 线程的启动只能由一次,否则抛出异常 (无效线程状态异常 IllegalThreadStateException )
4. 可以直接创建Thread类的对象并启动该线程,但是如果没有重写run(),什么也不执行。
5. 匿名内部类的线程实现方式
线程的创建方式:
1. 方式一:继承Thread类,并重写run()
1.1 共享数据的( 静态属性 面向对象的单例 )
1.2 单继承
1.3 在加锁的时候很麻烦,需要进行区分使用的变量是否是静态的,如果是使用类的Class对象作为锁,
否则使用this作为锁。
创建线程的第二种方式:实现Runable接口
步骤:
1,定义类实现Runnable接口
2,覆盖Runnable接口中的run方法。
将线程要运行的代码存放在该run方法中。
3,通过Thread类建立线程对象。
4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象传递给Thread的构造函数。
因为,自定义的run方法所属的对象是Runnable接口的子类对象。
所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
实现方式和继承方式有什么区别呢?
实现方式好处:避免了单继承的局限性。
在定义线程时,建立使用实现方式。
两种方式区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。
class Demo8
{
public static void main(String[] args)
{
new Thread(new Runnable(){
public void run()
{
System.out.println(Thread.currentThread().getName()+"Runnable...........");
}})
{
public void run()
{
System.out.println("Thread.........");
}
}.start();
System.out.println("Hello World!");
}
}
/*匿名内部类
结论:如果执行线程时,即继承了Thread的run方法,又实现了Runnable的run方法时,执行的是Thread的run方法,
不是Runnable的run方法。*/
如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证,发现不在是this。因为静态方法中也不可以定义this。
静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
类名.class 该对象的类型是Class
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class
主线程和子线程交替运行
子线程先运行50次,在主线程运行100次,然后主线程和子线程交替运行。
例1:
class SonThread implements Runnable
{
boolean tag = true;
public void run()
{
for(int y=1;y<=50;y++)
{
synchronized(ThreadTest.class)
{
if(!tag)
{
try
{
ThreadTest.class.wait();
}
catch (Exception e)
{
}
}
for(int x =1;x<=50;x++)
{
System.out.println("子线程..... "+x);
}
tag = false;
ThreadTest.class.notify();
}
}
}
}
class ThreadTest
{
public static void main(String[] args)
{
SonThread s = new SonThread();
Thread t = new Thread(s);
t.start();
for(int y =1;y<=50;y++)
{
synchronized(ThreadTest.class)
{
if(s.tag)
{
try
{
ThreadTest.class.wait();
}
catch (Exception e)
{
}
}
for(int x =1;x<=100;x++)
{
System.out.println("主线程..... "+x);
}
s.tag = true;
ThreadTest.class.notify();
}
}
System.out.println("Hello World!");
}
}
例4:
/*单例设计模式的线程同步;*/
class Ticket
{
static int tick = 50;
private static Ticket ticket = new Ticket();
private Ticket()
{
}
public static Ticket getInstance()
{
return ticket;
}
public void setTic(int x)
{
this.tick = x;
}
public int getTic()
{
return this.tick;
}
}
class SellTick extends Thread
{
Ticket ticket = null;
public SellTick(Ticket ticket,String name)
{
super(name);
this.ticket = ticket;
}
public void run()
{
while(true)
{
synchronized(SellTick.class) //this
{
if(ticket.getTic()>0)
{
System.out.println(this.getName()+":买票"+ticket.getTic());
int num = ticket.getTic();
ticket.setTic(--num);
}
else
{
System.out.println("票已经售完,请明天再来"); break;
}
}
}
}
}
例5:
class Demo5
{
public static void main(String[] args)
{
Ticket ticket = Ticket.getInstance();
SellTick t1 = new SellTick(ticket,"1号");
SellTick t2 = new SellTick(ticket,"2号");
t1.start();
t2.start();
System.out.println("Hello World!");
}
}
例6:
package Itcast;
/*模拟一个软件的升级过程;*/
class UpdateVersion implements Runnable
{
public void run()
{
int i = 0;
while(true)
{
System.out.println(Thread.currentThread().getName()+"数据检索中。。。。。。。"+","+i++);
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
//e.printStackTrace();
}
if(i == 100)
{
System.out.println(Thread.currentThread().getName()+"版本需要更新。。。。。"+i);
break;
}
}
}
}
public class Program
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
UpdateVersion v = new UpdateVersion();
Thread t = new Thread(v,"迅雷");
t.start();
System.out.println("Hello World!");
}
}
例7:
/*
死锁:
当多个线程同时获取多个共享资源时,有可能会发生死锁状态,死锁不可接触,只能在设计时人为地避免。
一下是通过连个不同的字节码文件对象作为锁。
class DeadLock implements Runnable
{
private boolean b;
DeadLock(boolean b)
{
this.b = b;
}
public void run()
{
if(b)
{
while(true)
{
synchronized(DeadLock.class)
{
System.out.println(Thread.currentThread().getName()+", "+"lock1");
synchronized(DeadLockTest.class)
{
System.out.println(Thread.currentThread().getName()+", "+"lock2");
}
}
}
}
else
{
while(true)
{
synchronized(DeadLockTest.class)
{
System.out.println(Thread.currentThread().getName()+", "+"lock2");
synchronized(DeadLock.class)
{
System.out.println(Thread.currentThread().getName()+", "+"lock1");
}
}
}
}
}
}
public class DeadLockTest
{
public static void main(String[] args)
{
DeadLock d1 = new DeadLock(true);
DeadLock d2 = new DeadLock(false);
Thread th1 = new Thread(d1);
Thread th2 = new Thread(d2);
th1.start();
th2.start();
System.out.println("Hello World!");
}
}
例8: 死锁。
同步中嵌套同步。
class Ticket implements Runnable
{
private int tick = 1000;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(obj)
{
show();
}
}
}
else
while(true)
show();
}
public synchronized void show()//this
{
synchronized(obj)
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);
}
}
}
}
class DeadLockDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.flag = false;
t2.start();
}
}
来源: http://blog.csdn.net/seashouwang/article/details/7879632