首页 JAVA程序设计课堂笔记整理java课堂笔记

JAVA程序设计课堂笔记整理java课堂笔记

举报
开通vip

JAVA程序设计课堂笔记整理java课堂笔记目录 2第一课 Java技术的历史 2Java的历史 2Jdk的安装 2Java运行环境的配置 2第二课 Java程序 2类 3变量 4变量的类型转换 6逻辑运算符 9第三课 Java分支结构 9If 10Switch 10While 12*System.in.read() 12数组 14第四课 类和对象 14类和对象 15封装性(private) 16构造方法: 18匿名对象 19第五课 Java方法 19递归 20...

JAVA程序设计课堂笔记整理java课堂笔记
目录 2第一课 Java技术的历史 2Java的历史 2Jdk的安装 2Java运行环境的配置 2第二课 Java程序 2类 3变量 4变量的类型转换 6逻辑运算符 9第三课 Java分支结构 9If 10Switch 10While 12*System.in.read() 12数组 14第四课 类和对象 14类和对象 15封装性(private) 16构造 方法 快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载 : 18匿名对象 19第五课 Java方法 19递归 20方法重载 21Java新技术 22第六课 关键字this、static 22This 24Static 25第七课 内部类、继承、封装、方法的重写 25单态 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 模式 26对象数组 27程序的代码块 29内部类 31封装 31继承 33方法的重写 35第八课 final、抽象类、接口、多态 35final关键字 35抽象类 36接口 37对象转型和instanceof关键字 39多态(动态绑定,池绑定) 42第九次课 包、异常 42包 43JDK1.5的新特性:静态导入 44异常 44异常的处理机制 47第十次课 finally、throw、throws和自定义异常 47finally 47throws子句 48throw语句 50自定义异常 52垃圾回收机制:finalize()方法 53第十一次课 线程、线程同步 53线程的概念 53线程的两种创建和启动方法 57Runnable与Thread的区别 59线程同步 63死锁 65第十二次课 进程通信 65后台线程 67线程的优先级 68线程的通信 71第十三次课 集合 72集合类型 76Iterator接口 78第十四次课 IO系统 第一课 Java技术的历史 Java的历史 Jdk的安装 Java运行环境的配置 第二课 Java程序 类 1、类封装了一类对象的状态和方法,是用来定义对象的模板。 基本格式如下: Class 类名 { 变量; 方法; } 例:class Hello {public static void main(String args[]) {System.out.println(“Hello”); } } 运行程序时输入的是:java 类名(因此必须注意文件名与类名不同的情况)。 小结:public类,类名必须与文件名一致。 一个文件中若有多个类,在编译时则会生成相应多个class文件(即字节码程序) 在一个.java文件中,只能有一个public类,且类名与public类名一致 2、 注释语句 作用:解释说明,方便用户; 调试程序 3种注释形式: a. // 单行注释 b./* */多行注释 c./** */ class Test01 { //此为单行注释,从//到本行结束,所有字符会被编译器忽略 /* 此为多行注释,/**/之间的说有字符会被编译器忽略 */ /** 此为多行注释,之间的所有字符会被编译器忽略,且会作为JavaDoc文档的内容 / pubic static void main( String[]args) { System.out.println(“注释演示”); } } 变量 程序的基本功能就是处理数据,程序用变量来 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示数据 变量的分类 变量的类型转换 1.变量命名规则:标识符的首字符必须是字母,下划线“_”, 美元符号“$”。 标示符不能用关键字命名,其中Java有49个关键字,以及goto和const两个保留字。true 和false不是保留字,但也不能作变量,因为有唯一的编译意义。 2. 类型转换 隐式(自动):从精度小往精度大的数据类型转换; 显式(强制):从精度大往精度小的数据类型转换。(这种转换会损失数据的精度,所以需要显式转换) 小结:隐式转换: Char-> int Byte->short->int->long Int->float->double 如果碰到字符串类型,那么所有类型都要向字符串类型转换 例2—1 class Test21 { public static void main(String[] args) { int x=266; byte y=(byte)x; System.out.println("x= "+x); System.out.println("y= "+y); } } 运行结果:x=226 y=10 266超过byte类型的数据的最大值,造成溢出,显式转换后,损失了精度 数值的溢出 3.数据溢出 例:2—2求整型的最大值、最小值 class Test22 {public static void main(String [] args) { int max=Integer.MAX_VALUE; //获取INT型数据的最大值 int min= Integer.MIN_VALUE; //获取INT型数据的最小值 System.out.println(max); System.out.println(max+1); System.out.println(min); System.out.println(min-1); } } 运行结果:2147483647 -2147483648 -2147483648 2147483647 小结:溢出时, Max+1 ——> 最小; Min-1 ——> 最大: class Test23 { public static void main(String [] ar) { int c=12; Long d=66666; Float f=1e-20f; Double g=3.14e-300; Double result=f*g; System.out.println(”f=”+f); System.out.println(”g=”+g); System.out.println(”result=”+result); g=1234.123456789; c=(int)d; f=(float)g; System.out.println(”c=”+c); System.out.println(”d=”+d); System.out.println(”f=”+f); System.out.println(”g=”+g); } } 运行结果:f=1.0e-20 g=3.14e-300 result=3.14e-320 c=66666 d=66666 f=1234.1234 g=1234.123456789 4.变量的生命周期 变量可分为: 成员变量:在类中声明,它的作用域是整个类 局部变量:在一个方法或一个代码块声明,它的作用域是该方法或该代码块 方法参数:它的作用域是该方法 异常处理参数: 变量的作用域决定了生命周期。 class Test24 { int a;//成员变量 public static void main(String[] args) { int x=23;//局部变量,其作用域为该main方法 { int x=23;//局部变量,其作用域是该{}代码块,由于该代码 //块在main方法内,所以这里定义的x会与上面 //定义的x冲突 System.out.println(x); } //复合语句 System.out.println(x); } } 小结:复合语句的变量到复合语句外便失效。 复合语句外面和里面不能重复定义同一个变量。 逻辑运算符 1. 运算符(/,%) 小结:取模运算(%),负号在模数上时,忽略不计; 取整符号(/)的运算特点。 例:0——9的不断循环 Class 25 {public static void main (String [] ar) { int x=0; While(true) x=(x+1)%10; System.out.println(x); } } 例2—4:有x个人,6人一房,求房数。 class Test26 { public static void main(String [] ag) {int x=Integer.parseInt(ag[0]); Int y=(x+5)/6; System.out.println(y); } } class 27 { public static void main(String [] args) { int x=Integer.parseInt(args[0]); int y= - x%2; System.out.println(y); } } 运行结果:(输入java He 99)//使用了命令行参数的模式,创建了一个string[] args变量 -1 (输入java He 100) 0 class Test28 { public static void main(String [] args) { int x=Integer.parseInt(args[0]); int y=x%-2; System.out.println(y); } } 运行结果:(输入java She 99) 1 (输入java She 100) 0 小结:%对“-”的处理,如果是在分子上,可见该式子看成-(x%2) 如果在分母上,这忽略不计 2.&与&&的区别 &:不管第一个条件为真为假,都必须判断第二个条件 &&:当第一个条件为真时,才判断第二个条件的真假,如果第一个条件为假,则整个式子返回flase; public class Test29 { public static void main(String []args) { int x=1,y=0; if(x!=1&&x/y==0)//编译通过 //if(x!=1&x/y==0)//编译错误 System.out.println(x); else System.out.println(y);} } 3. “+”的作用: 字符串中的连接符:第一个“+”运算符做的是字符连接操作时,所有数据向字符串类型转换 运算相加:第一个“+”运算符做的是运算相加(即有数值类型数据参加运算),所有数据向int型转换 例:class Test210 {public static void main(String [] args) {System.out.println(‘a’+1+” ”); System.out.println(“ ”+(‘a’+1)); System.out.println(“ ”+‘a’+1); System.out.println(‘a’+1); } } 运算结果:98 98 a1 98 4. 比较操作符(<, >, <=, >=, = =, !=) 小结:用来比较两个值的关系,运算结果是boolean型。 比较操作符的结合方向是从左到右。 “= =”和“!=”的操作元既可以是基本类型,也可以是引用类型。 5. 位运算符(&,|,^,~,>>,>>>,<<) “&,|,^, ~”是按位运算的,是将两个操作元的每个二进制位进行与、或、异或、取反运算。 “》,《”是算术移位运算,“>>>”是逻辑移位运算。 小结:对操作元进行移位运算后,并没有改变操作元本身的数据。 对于“》”算术右移位运算的规则:右移N位,相当于除以2^N 方法:将操作数的二进制位向右移N位; 高位补零(原为正数),高位补1(原为负数)。 对于“《”算术左移位运算的规则:左移N位,相当于乘以2^N 方法:将操作数的二进制位向左移N位; 低位补零。 对于“>>>”无符号右移位运算的方法: 将操作数的二进制位向右移N位; 高位补零,零扩展。 对于低于int型的操作数将先自动转换为int型,再进行移位运算。 根据位运算符的运算特点,求解特殊的运算。 例:求2^x,用System.out.println(1< 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 ;OOD:面向对象的设计;OOP:面向对象的程序。 比较面向过程和面向对象: (1) 面向过程: person() { char name[12]; int age; } talk() { } (2) 面向对象: person { String name; int age; void talk() {} } 属性、方法都是类的成员(变量) 小结:产生一个对象; 产生多个对象:如: Person per = new Person(); Person per1 = new Person(); 对象之间没有联系; 对象之间可以相互赋值(对象引用的传递),如: Per1 =null; Per1 =per; //此时两个引用指向同一个堆内存。 (对象赋值后之前已生成的空间会自动断开) 例:class Person { String name; int age; void talk() { System.out.println("my name is:"+name+ "i am:"+age); } } class A { public static void main(String [] agrs) { Person per=new Person(); per.name="zhangsan"; per.age=10; per.talk(); } }; 运行结果:my name is:zhuangsan I an:10 小结:面向对象编程三大特点:封装性,继承性、多态性 封装性(private) 其核心思想史将数据和对数据的操作封装在一起。封装是指隐藏对象的属性和实现细节,仅仅对外公开接口。Java主要通过访问控制机制来进行封装,这种机制能控制对象的属性和方法的可访问性。 4种访问控制级别: public:对外公开,访问级别最高;protected:只对同一个包中的类或者子类公开; 默认:只对同一个包中的类公开;private:不对外公开,只能在对象内部访问。 一般静态属性会加保护private,可以防止使用者错误地修改属性。而对其输入所实施的保护可以在各个方法中添加条件,从而控制输出。公有的方法去引用,如:setter getter 例:class Person { private String name; private int age; public void setName(String m) //方法名首字符小写 { name=m;} public void setAge(int n) { if(n<0||n>180) //控制输出条件 System.out.println("error"); else age=n;} public String getName() { return name;} public int getAge() {return age;} void talk() { System.out.println("my name is:"+getName()+" " +"i am:"+getAge()); } } class C { public static void main(String [] agrs) { Person per=new Person(); per.setName("zhangsan"); per.setAge(200); per.talk(); } } 运行结果:error my name is:zhuangsan I an:0 构造方法: 构造方法的3个特点: a、名称和类名称一样; b、没的方法的返回类型(外) c、方法内,不能用return 进行返回 构造方法被系统(JVM)自动调用,只要有对象生成,就要调用构造方法。 构造方法负责对象的初始化工作,为实例变量赋予合适的初始值。当用new创建内存时必须运行构造方法。 注意:构造方法也可以重载,产生对象必须调用相应的构造方法。 Java中每一个类都一有默认的构造方法,它是无参的。 但是,一旦写了一个有参数的构造方法,默认的构造方法就没有了。 例:class Person { private String name; private int age; int date; public Person() { } public Person(String n) {name=n;} public Person(String n,int m) {name=n; if(m<0||m>180) System.out.println("age is error"); else age=m; } public Person(String n,int m,int i) {name=n; if(m<0||m>180) System.out.println("age is error"); else age=m; if(i<1||i>7) System.out.println("date is error"); else date=i; } void talk() { System.out.println("my name is:"+name+" " +"i am:"+age+" " +"the date is:"+date); } } class E { public static void main(String [] agrs) { Person per=new Person("zs"); Person a =new Person(); Person b =new Person("linan",178); Person c =new Person("maya",12,8); Person d =new Person("yaya",12,6); per.talk(); a.talk(); b.talk(); c.talk(); d.talk(); } } 运行结果:date is error my name is:zs I am:0 the date is:0 my name is:null I am:0 the date is:0 my name is:linan I am:178 the date is:0 my name is:maya I am:12 the date is:0 my name is: yaya I am:12 the date is:6 匿名对象:只使用一次 匿名对象是在一个对象被创建之后,调用对象的方法时可以不定义对象的引用变量,而直接调用这个对象的方法。如:new Person(“huang”,10).talk(); 它使用在以下2种情况: (1) 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象; (2) 将匿名对象作为实参传递给一个方法调用。 其他程序: 1、class Person { String name; //属性 int age; void talk() //方法 { System.out.println("my name is:"+name+ " my age is :"+age); } } class Lesson2 { public static void main(String[] agr) { Person per = new Person(); Person per1 = new Person(); //per1=null; per1=per; //对象赋值 per.name="zs"; per.age=10; per.talk(); per1.name="li"; per1.age=-10; per1.talk(); } } 2、class Person { String name; //属性 int age; public Person(){} public Person(String n) { name=n; System.out.println("i am here"); } public Person(String n,int a) { age=a; name=n; } void talk() //方法 { System.out.println("my name is:"+name+ " my age is :"+age); } } class Lesson5 { public static void main(String[] agr) { new Person("huang",10).talk(); } } 第五课 Java方法 递归 定义:简单的说,一个方法如果调用了本身,那么这个方法就是递归。递归函数一定要有一个结束的条件,作为函数的出口,要不然就会成为死调用。 斐波那契数列递归算法及求和 public class Test401 {public static void main(String args[]) {int n=Integer.parseInt(args[0]); int []a=new int[n]; int sum = 0; for (int i = 0; i < a.length; i++) { System.out.print(func(i)+" "); sum +=func(i); } System.out.println("sum=" + sum); } public static int func(int x) {if (x==1||x==0)//函数的出口 return 1; else return (func(x - 1) + func(x - 2)); } } 结果:(输入)java Test310 8 (输出) 1 1 2 3 5 8 13 21 sum=54 方法重载 方法重载:多态的表现。同一种功能,有多种实现方式,采用哪种实现方式,取决于调用者给定的参数,即根据实际情况而定。这就引进了方法重载的思想。 小结:方法重载:方法名一样,参数列表(参数个数,参数类型)不一样; 方法的返回类型不一样,参数列表一样,不构成重载; 例:class Test402 {public static void main(String [] args) { System.out.println(add(3,4)); System.out.println(add(3,4,5)); System.out.println(add(3,4f,5)); } static int add(int a,int b) { int z=a+b; return z; } static int add(int a,int b,int c) { int z=a+b+c; return z; } static float add(int a,float b,int c) { float z=a+b+c; return z; } } 结果:7 12 12.0 Java新技术 1.foreach:foreach语句是java5的新特征之一,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本。 foreach的语句格式: for(元素类型t 元素变量x : 遍历对象obj){      引用了x的java语句; } 例子:数组的打印 public class Test403 { public static void main(String args[]){ int a[]=new int[]{5,9,8,7,6,2}; for(int i:a){ System.out.print(i+" "); } } } 运行结果: 5 9 8 7 6 2 2. 可变参数:Java语言在jdk1.5中推出可变参数,variable arguments,或简称varargs。这一新语言特征给软件开发人员在编写方法重载时提供了方便和灵活性。但可变参数的应用并不像想象的那么简单,使用时有其特殊要求和局限性。在方法的重载中得到了很好的体现。 例子 public class Test404 { public static void main(String[] args) { fun(); fun(2); fun(2,4,6); int []a=ch(); fun(a); } static int[] ch() { int b[]={1,3,5,7}; return b; } static void print(int []b) { for(int i:b) { System.out.print(i+" "); } } static void fun(int ...arg){ for(int i:arg) { System.out.print(i+" "); } System.out.println(); } } 运行结果:2 2 4 6 1 3 5 7 第六课 关键字this、static This 1.调用类中的属性:this.属性名。如: class Person { String name; int age; public Person(String name,int age) { this.name=name; this.age=age; } 2. 调用类中的方法:this.方法名。 3. 调用类中的构造:this()。注意:一定要放在第一句,否则会出错;当彼此都要调用this时,必须有一个没有this的构造方法。如: class Person { private String name; int age; public Person() { this(); System.out.println("i am here"); } public Person(String name) { this.name=name; } public Person(String name,int age) { this(name); this.age=age; } public void setName(String name) { this.name=name;} public String getName() { return this.name; } public void getInfo() { System.out.println(this.getName()+" "+age); } }; class Lesson4 { public static void main(String[] args) { Person p=new Person(); Person p2=new Person(); p.getInfo(); } } 4.指当前对象:this。如: class Person { public void print() { System.out.println(this); } }; class Lesson5 { public static void main(String[] args) { Person p=new Person(); Person p1=new Person(); System.out.println(p); Static 1. 当任何一个引用改变时,所有对象都会改变。如: class Student { String name; int age; static String school="GDPU"; public Student(String name,int age) { this.name=name; this.age=age; } public void setSchool(String school) { this.school=school; } }; class Lesson6 { public static void main(String[] args) { Student st1=new Student("zs",12); Student st2=new Student("zs",12); Student st3=new Student("zs",12); Student.school="zhong"; System.out.println(st1.school); } } 2.static可以修饰属性,方法,全局数据区。 3.静态方法不能调用非静态方法。如: class Lesson7 { public static void main(String[] args) { fun(); } public static void fun () //不能是public void fun() { System.out.println("st1.school"); } } 第七课 内部类、继承、封装、方法的重写 单态设计模式 所谓单态设计模式(即是类在内存中只能创建一个实例对象)就是采取一定的方法保证在整个的软件系统中,对某个类只能产生一个对象实例,并且该类只提供一个取得其实例对象的方法.如果我们要让类在一个虚拟机中只能产生一个对象.我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象. 构造方法私有化;整个系统中只有一个实例化对象,不能产生多个对象,如回收站 例程(1) class Student { String name; Student (){} Student (String name) {this. name=name;}//若加上private,这个构造方法就被私有化了,那其它类生成对象的话就不能调用这个构造方法了 void by() {System.out.println(name);} }; class lesson2 { public static void main(String[] args) { new Student ("li");//若Student类中带有一个参数的构造方法被私有化了,那这里就不能调用已被私有化的构造方法 } } 分析:若加上private,编译会出错,若没加上private,编译就会通过。由这个例子可以看出我们可以利用private来对构造方法进行私有化 例程(2) class Student { String name; static Student s=new Student("li"); Student (){} private Student (String name){this.name=name;} void by() {System.out.println(name);} public static Student get() {return s;} }; class lesson3 { public static void main(String[] args) { Student s1=Student.get(); //s1和s2是同一个对象,这就是单态设计模式,整个系统中只能生成一个实例 Student s2=Student.get(); System.out.println(s1==s2); } } 运行结果:true 分析:(1)static修饰的属性或方法将来不会放在堆内存里面,有一个专门的存放空间,即是全局数据区。 (2)static修饰的属性或方法会被将来的所有的对象所共用,即是,有static属性,无论产生多少个对象,所有的对象都会指向同一个static存放的空间,这就是为什么单态设计模式中,整个系统只能生成一个实例。 (3)程序的内存划分 A.堆内存 B.栈内存 C.全局代码区 D.全局数据区 对象数组 例程 class Student { String name; Student(String name){this.name=name;} }; class lesson4 { public static void main(String[] args) { Student []s=new Student[2]; //创建对象数组 s[0]=new Student("zhansan"); //动态初始化 s[1]=new Student("lisi"); for (int i=0;i 办法 鲁班奖评选办法下载鲁班奖评选办法下载鲁班奖评选办法下载企业年金办法下载企业年金办法下载 引用它们。必须在创建时,作为new语句的一部分来声明它们。 这就要采用另一种形式的new语句,如下所示: new <类或接口> <类的主体> 这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。它还创建那个类的一个新实例,并把它作为语句的结果而返回。 匿名内部类一般是在抽象类和接口的基础上使用: interface A{ void print(); } class B implements A{ public void print(){System.out.println("huang");} }; class C{ public void fun1(A a){ a.print();} public void fun2(){ fun1(new B()); }}; class Lesson10{ public static void main(String[] args) { C c=new C(); c.fun2(); }} interface A{ void print(); } class C{ public void fun1(A a){ a.print();} public void fun2(){ fun1(new A(){ public void print(){System.out.println("huang");}}); }}; class Lesson10{ public static void main(String[] args) { C c=new C(); c.fun2(); }} 注意:是在new A() 后面加上{ },再在里面重写方法 封装 封装:   是指隐藏属性,方法或实现细节的过程.仅对外公开接口. 封装的最大优点是:        1.便于使用者正确.方便地理解和使用.防止使用者错误的修改系统属性.        2.清楚的体现了系统之间的松散耦合关系,提高系统的独立性.        3.提高软件的可重用性.                 封装提供了4种访问控制级别:  public:公有的.最高的访问级别所有的类都可以访问.所有的类都可  以访问. protected:(受保护的)只对同一个包中的类或者子类公开访问. private:私有的.不对外公开,只能在对象内部访问,访问级别最低. default:默认的,当前目录(包)下的类可以访问.  系统的封装程度越高,相对独立性就越强.而且使用也方便.  当然现实生活中这样的例子多之更多.例如:我们常使用的手机就是个明显的例子.我们用手机只注重手机的品牌价格和接听收发短信玩游戏的功能.但是我们没有必要知道手机的内部是什么.他是怎样实现 这样的功能的我们都是不可见的.这就是商家把一些技术的东西让我们不可见.我们看见的只是漂亮的外壳和它最基本的更重功能. 所以.封装是个很重要的概念.封装好你的程序,它将更加独立美观. 继承 1.继承可以扩展类的功能 2.继承只能是单继承,一个子类只能继承一个父类 3.继承可以有多层继承(继承有传递性) 4.子类不能直接访问父类的私有成员,但可以通过方法调用来处理 5.子类实例化时,先调用父类的构造方法,再调用自己的构造方法(子类构造方法中隐藏一个super()方法,用于调用父类的构造方法) 例程(1) class Teacher { String name; int age; Teacher(){} //没有这个语句的话编译不通过,因为main()中调用的是无参的构造方法 Teacher(String name){this.name=name;} void teach() {System.out.println(name);} }; class Student extends Teacher //这样Student类可以继承一些Teacher类中已经写好的属性和方法 { String school="GDPU"; //这里可以扩充父类中没有的内容 }; class lesson11 { public static void main(String[] args) { Student s=new Student(); //生成子类实例 s.name="zhansan"; //name属性是从Teacher类中继承的 s.age=10; //age属性也是从Teacherl类中继承的 s.teach(); //子类继承了父类的方法 } } 运行结果:zhansan 分析:由例程(1)可以看出,继承可以减少代码的重复 例程(2) class Teacher { private String name; //把父类的name属性私有化 int age; Teacher(){} Teacher(String name){this.name=name;} void teach() {System.out.println(name);} }; class Student extends Teacher { String school="GDPU"; }; class lesson12 { public static void main(String[] args) { Student s=new Student(); s.name="zhansan"; //子类不能访问父类的私有成员 s.age=10; s.teach(); } } 分析:(1)这个例程编译出错,因为子类不能访问父类的私有成员name (2)当要实例化时,先调用子类的构造方法,再调用相应的父类的构造方法,产生父类对象,才能产生子类对象 (3)Student类中默认的构造方法是Student(){super();} Super()的作用是子类调用父类的构造方法,若是super(“lisi”),就是调用Teacher(String name){this.name},若是super(),就是调用Teacher(){} 方法的重写 1.子类定义了与父类相同的方法,如果重写成功,则子类实例化时调用 的将会是子类中重写过的方法,而不会去调用父类的此方法。如果重 写不成功,则子类实例化时调用的将会父类的方法 2.被重写的方法不能拥有比父类更严格的权限。 3.如果父类的方法加上了private,则要注意,此时子类是不能对它进行重写的,只能说是重新建立了一个新的方法 4.重写成功的话,要想再调用父类的方法,用super.方法名(); 例程(1) class Father { String name="Tom"; int age; Father(){} Father(String name){this.name=name;} void teach() {System.out.println(name);} }; class Son extends Father { String name="Tom.son"; //属性的覆盖 String school="GDPU"; Son(){} //这里有默认的super() }; class lesson13 { public static void main(String[] args) { Son s=new Son(); s.teach(); } } 运行结果:Tom 分析:为什么打印的是父亲的名字呢?因为生成儿子的对象,再去调用teach()这个方法,这个方法是在父亲里面,所以打印的name是父亲的 例程(2) 把例程(1)的Son类改为 class Son extends Father { String name="Tom.son"; String school="GDPU"; Son(){} void teach() //跟父类的teach()方法一摸一样,这样把父类中的teach()方法覆盖了 {System.out.println(name);} }; 运行结果:Tom.son 分析:(1)方法重写成功的话,调用的方法是子类的方法,若是重写不成功,调用的是父类的方法,现在重写成功了,所以调用的是子类中的teach()方法 (2)这里父类的teach()方法前面不能加public,因为方法重写时,子类的权限要比父类的大 例程(3) class Father { String name="Tom"; int age; Father(){} Father(String name){this.name=name;} void teach() //这里没加上private {System.out.println(name);} public void fun() //fun()用于调用teach() {teach();} }; class Son extends Father { String name="Tom.son"; String school="GDPU"; Son(){} void teach() //重写父类的teach()方法 {System.out.println(name);} }; class lesson14 { public static void main(String[] args) { Son s=new Son(); s.fun(); } } 运行结果:Tom.son 分析:(1)打印的是子类的名字,说明子类中的teach()重写是成功的,若重写成功,那子类对象调用的都是调用子类重写的方法。 (2)若在父类中的teach()方法前面加上private属性,那运行结果是Tom,说明此时子类重写teach()不成功,所以调用的是父类的方法。子类不能重写父类中私有的方法,即使方法名相似,也只能算是新建方法。 第八课 final、抽象类、接口、多态 final关键字 final关键字 1.声明类:不能有子类(此时为最终类) 2.声明方法:不能被子类重写 3.声明变量:将成为常量,不可修改,一般要大写 使用public static final声明的常量称为全局常量 final可以修饰非抽象类,非抽象成员方法和变量,但不能用来修饰构造方法。如果把类定义为final类型,则该类不能被继承。 Final的特征: 1、 final修饰变量,则表示常量。例:final String name=”huang”(常量) 2、 public static final String NAME=”huang”(全局常量) 3、 final变量只能赋一次值 注意:形参调用内部类,则形参前必须有final修饰。 Final的作用: 1、 提高程序的安全性 2、 提高程序代码的可维护性 3、 提高程序代码的可读性 抽象类 定义:只要类中的有一个或多个方法没有具体实现,即含有抽象方法,(抽象方法)前有abstract修饰,此类称为抽象类。 例:abstract class A {public abstract void fun(); } 抽象类的特点: 1、 抽象类不能实例化,只能被继承 2、 抽象类中默认的构造方法,但构造方法不能直接调用,只能由子类去重写 3、 抽象类不能被final修饰 例:abstract class A1 {String name; A1(){System.out.println("H!!!");} A1(String name){this.name=name;} public abstract void fun(); } class A2 extends A1 { A2(){super();} public void fun() { System.out.println("hee"); } } class A { public static void main(String[] args) { A2 b=new A2(); } }。 运行结果:H!!! 接口 由抽象方法和全局变量组成。所有的成员都是public类型的。 在Java中,接口包括: 1、 概念性的接口(指系统对外提供的所有服务) 2、 用interface定义的实实在在的接口(即接口类型) 接口的特征: 1、 接口中的成员变量默认都是public、static、final类型,必须被显式初始化 2、 接口中的方法默认都是public、abstract类型的 3、 接口中只能包含public、static、final类型的成员变量和public、abstract类型的方法 4、 接口没有构造方法,不能被实例化 5、 一个接口不能实现另一个接口,但它可以继承多个其他接口 Abstract class A { public static final String NAME=”huang”; public abstract void fun(); public abstract void print(); } Interface A { String NAME=”huang”; void fun(); void print(); } 小结:接口,即一个抽象类的变量全为抽象方法和全局变量 接口是用来继承的,用implements实现接口 一个类可以实现多个接口,但只能继承一个父类 interface A { String NAME="huang"; void fun(); void print(); } interface D { } class B1 implements A,D {B1(){super();} public void fun() {System.out.println("HEEE");} public void print(){} } class B { public static void main(String[] args) { B1 b=new B1(); } } 接口的好处: 1. 通过接口可以实现多“继承”,一个类只能有一个直接父类,但可以实现多个接口 2. 通过接口可以提高程序的封装性:用户不需要知道接口的具体实现方式;提高各模块的松耦性,从而提高程序的安全性和拓展性:系统增加或修改某一功能模块时,只要保持接口不变,不用改动整个系统。 3. 接口可以作为一种标准使用,例如电器的电源接口。该接口的提出可以让所有的厂家生产的电器使用同一种电源。 对象转型和instanceof关键字 对象转型:指当有继承发生时,父类对象和子类对象的相互转换。 有两种转型:1、向上转型,系统自动完成; 2、 向下转型,此时要进行类型转型(强制)。 例:class Animal { String name; public void cry() {System.out.println(name+"animal cry"); } } class Dog extends Animal { int legs=4; Dog(String name){this.name=name;} public void cry() {System.out.println(name+"dog wang ...."); } } class C { public static void main(String[] args) { Dog d=new Dog("blackdog"); d.cry(); } } 运行结果:blackdog dog wang .... 又例:class Animal { String name; Animal(String name){this.name=name;} public void cry() {System.out.println(name+" animal cry"); } } class Dog extends Animal { int legs=4; Dog(String name){super(name);} public void cry() {System.out.println(name+" dog wang ...."); } } class D { public static void main(String[] args) { Animal a=new Dog("blackdog"); a.cry(); System.out.println(a.name); Dog d=(Dog)a; System.out.println(d.legs); System.out.println(a instanceof Animal); System.out.println(d instanceof Dog); Animal a1=new Animal("whitedog"); a1.cry(); System.out.println(a1 instanceof Dog); } } 运行结果:blackdog dog wang… blackdog 4 true true whitedog animal cry false 小结:instanceof可以判断一个对象是一个类或子类的实例,结果为true,false。结果为TRUE时,则对象之间可以进行类型转型;若为FALSE,则对象之间不可以进行类型转型。 多态(动态绑定,池绑定) 只是针对方法而言。在运行期间,判断对象的世界类型。根据实际类型,对方法进行调用。 向下转型的应用:Dog d=(Dog) a; System.out.println(d.legs); 这样便可以输出Dog类中的属性了。 但Animal a=new Animal(“blackdog”); Dog d=(Dog) a; System.out.println(d.legs); 由于d和a之间没有联系(没有指向),因此在执行过程中发生异常。 多态的表现形式(3种): 1、 方法重写;2、方法重载;3、对象多态性(向上转型,向下转型) 多态发生的条件: 1、 有继承发生;2、有方法重写;3、父类引用指向子类对象(向上转型) 例:class Animal { String name; Animal(String name){this.name=name;} public void cry() {System.out.println(name+" animal cry"); } } class Dog extends Animal { int legs=4; Dog(String name){super(name);} public void cry() {System.out.println(name+" dog wang ...."); } } class Cat extends Animal { int beard=2; Cat(String name){super(name);} public void cry() {System.out.println(name+" cat miao ...."); } } class E { public static void main(String[] args) { f(new Dog("blackdog")); f(new Cat("whitecat")); } public static void f(Animal a) {a.cry(); if(a instanceof Dog) { Dog d=(Dog)a; System.out.println(d.legs); } if(a instanceof Cat) { Cat c=(Cat)a; System.out.println(c.beard); } } } 运行结果:blackdog dog wang… 4 Whitecat cat miao…. 2 例:class Animal { String name; Animal(String name){this.name=name;} public void cry() {System.out.println(name+" animal cry"); } } class Dog extends Animal { int legs=4; Dog(String name){super(name);} public void cry() {System.out.println(name+" dog wang ...."); } } class Cat extends Animal { int beard=2; Cat(String name){super(name);} public void cry() {System.out.println(name+" cat miao ...."); } } class Boy { String name; Animal pet; Boy(String name,Animal pet) { this.name=name; this.pet=pet; } void petCry() { pet.cry();} } class F { public static void main(String[] args) { Dog d=new Dog("blackdog"); Boy b=new Boy("xq",d); b.petCry(); Cat c=new Cat("whitecat"); Boy b1=new Boy("xh",c); b1.petCry(); } } 运行结果:blackdog dog wang… whitecat cat miao…. 编写模拟计算机USB接口功能的程序,USB接口可以插鼠标、MPS、U盘、键盘等外围设备。 interface Usb{ void start(); void stop(); } class Mouse implements Usb{ public void start(){System.out.println("mousestart");} public void stop(){System.out.println("mousestop");} } class Mps implements Usb{ public void start(){System.out.println("mpsstart");} public void stop(){System.out.println("mpsstop");} } class Upan implements Usb{ public void start(){System.out.println("upanstart");} public void stop(){System.out.println("upanstop");} } class Keyboard implements Usb{ public void start(){System.out.println("keyboardstart");} public void stop(){System.out.println("keyboardstop");} } class Bord{Usb p; Bord(Usb p){this.p=p;} void work(){ p.start();p.stop();} } class G{ public static void main(String[] args) { Usb n=new Mouse(); Usb s=new Mps(); Usb q=new Upan(); Usb t=new Keyboard(); new Bord(n).work(); new Bord(s).work(); new Bord(q).work(); new Bord(t).work(); } } 第九次课 包、异常 包 1.包的定义: 将多个类放在一起时,要保证类名不能重复。当声明的类很多时,类名就有可能冲突,这就需要一种机制来管理类名,这就是包。 包是Java提供的一种区别类名空间的机制,是类的组织方式,一个包对应一个文件夹,包中还可以有包,称为包等级,如同文件夹中可以有子文件夹。 同一个包中类名不能重复,不同包中可以有相同的类名。 2.系统包:Java提供了大量的类,为便于管理和使用,分为不同的包。这些包又称类库或API包,所谓API(application program interface)即应用程序接口。API包一方面提供丰富的类与方法供大家使用。 许多Java API包都以“java.”开头,以区别用户创建的包。 3.创建包 声明包语句格式为: package 自定义包名; 声明包语句必须添加在源程序的第一行,表示该文件的全部类都属于这个包。还可以在不同的文件中使用相同的声明包语句,这样就可将不同文件中的类都包含在相同的包中了,如同将不同的文件放在同一个文件夹中,以后其他类就可以引用这个包中创建好的类了。下面举例说明如何建立自定义包。 实例: package guo; //打包 import huang.Person;//导入包 class Lesson3 { public static void main(String[] args) { new huang.Person().print(); } } 打包编译的命令 Javac –d . 文件名.Java JDK1.5的新特性:静态导入 如果一个类中的所有方法都是静态的,则可用静态导入:import static 实例: package huang.guo; public class Compute{ public static int add(int x,int y){ return x+y; } public static int sub(int x,int y){ return x-y; } }; import static huang.guo.Compute.*; class Lesson7 { public static void main(String[] args) { System.out.println(add(1,2)); System.out.println(sub(1,2)); } } 异常 异常的引入: 1.异常是用来处理程序错误的有效机制。 2.在程序执行期间,会有许多意外的事件发生。例如,程序申请内存时没有申请到、对象还未创建就被使用、死循环等,都称为运行错误。 3.根据错误的性质将运行错误分为致命性错误和异常两种类型。 异常的定义: 1.运算时除数为0,或操作数超出数据范围,等,这类现象称为异常。 2.对于异常情况,可在源程序中加入异常处理代码,当程序出现异常时,由异常处理代码调整程序运行流程,使程序仍可正常运行直到正常结束。 3.由于异常是可以检测和处理的,所以产生了相应的异常处理机制。 异常的处理机制 1. 抛出异常 ava是这样规定的: 当语义限制被违反时,将会抛出(throw)异常,即产生一个异常事件,生成一个异常对象,并把它提交给运行系统,再由运行系统寻找相应的代码来处理异常。一个异常对象可以由Java虚拟机来产生,也可以由运行的方法生成。异常对象中包含了异常事件类型、程序运行状态等必要信息。 2. 捕获异常 异常抛出后,运行时系统从生成异常对象的代码开始,按方法的调用顺序进行查找,直到找到包含相应处理的方法代码,并把异常对象交给该方法为止,这个过程称为捕获(catch)异常。 异常处理机制就是: 当语义限制被违反时,将会抛出异常对象,并将引起程序流程从异常发生点转移到程序员指定的处理异常方法代码处进行异常处理。 3.异常处理语句格式为: · try {…} // 被监视的代码段,一旦发生异常,则交由其后的catch代码段处理 · catch (异常类型 e) {…} // 要处理的第一种异常 · catch (异常类型 e) {…} // 要处理的第二种异常 · … · finally {…} // 最终处理 实例: class Lesson5 { public static void main(String[] args) { int i=12,j=1; int a[]=new int [2]; System.out.println("begin"); System.out.println(i/j); System.out.println(a[2]); System.out.println("i am running"); System.out.println("end"); } } 运行结果:发生异常,数组越界,程序没有执行完(System.out.println("i am running");System.out.println("end");)没有执行。 class Lesson5 { public static void main(String[] args) { int i=12,j=1; int a[]=new int [2]; System.out.println("begin"); try { System.out.println(i/j); System.out.println(a[2]); } catch(Exception ea){System.out.println(ea);} finally {System.out.println("i am running");} System.out.println("end"); } } 运行结果:程序执行完(打印出end) try 和catch 是Java中用来处理异常的关键字,其作用如下: try语句 : 用来监视可能引起异常的语句,写程序时,应该将可能出现异常的语句代码放入此语句块中。 catch语句:异常发生时要执行的异常处理程序,它可以捕获到try{}语句块中抛出的异常对象,并可以按人为的要求进行异常信息的输出。 使用try ……catch语句,能保证程序发生异常时,仍能执行完成。 如果直到最后还是没有发现处理异常的catch语句,那么在finally子句执行完后,调用ThreadGroup的unCaughtException方法,终止当前的线程(即发生了异常的线程)。 如果希望在异常发生时能确保有一段代码被执行,那么应该使用finally子句。这样即使发生的异常与catch所能捕获的异常不匹配也会执行finally子句, 第十次课 finally、throw、throws和自定义异常 finally 在一般情况下都会执行,然而如果有System.exit( )时则不会运行。 例:class Lesson1 { public static void main(String[] args) { try { System.out.println(3/0); } catch (Exception e) { System.out.println(e); System.exit(1); } finally{ System.out.println("Hello World!");} } } 运行结果:java.lang.ArithmeticException:/by zero 小结:System.exit( )方法时终止当前正在运行的Java虚拟机。如果是非零数,则表示异常退出。因此,当程序执行完“System.exit(1);”时,不会再执行“finally{System.out.println(“Hello World!”);}”。 throws子句 用来表明一个方法可能会抛出的各种异常,但说明该方法会抛出但不捕获的异常。 注意:它用在方法声明处。当一个方法出现多种异常时,throws子句允许声明抛出多个异常。 例:class A {public int div(int x, int y)throws Exception { int t=x/y; return t; } } class Lesson2 { public static void main(String[] args) { A a=new A(); int m=0; 变量在方法中必须初始化 try { m=a.div(2,0); } catch (Exception e) { System.out.println(e); } System.out.println(m); System.out.println("Hello World!"); } } 运行结果:java.lang.ArithmeticException:/by zero 0 Hello World! 小结:main()方法可以throws异常,由Java虚拟机来捕获执行。 throws Exception 无论如何,一定要进行捕获。 throw语句 throw用在方法里面,可以明确地抛出一个异常,其后面要加一个异常类对象。 例:class Lesson3 { public static void main(String[] args) { try{ throw new Exception("play"); } catch(Exception e) { } System.out.println("main"); } } 运行结果:main 例:class A { public int div(int x, int y)throws Exception { int t=0; System.out.println("begin"); try { t=x/y; } catch (Exception e) { System.out.println(e); } System.out.println("end"); return t; } } class Lesson4 { public static void main(String[] args) { A a=new A(); int m=0; try { m=a.div(2,0); } catch (Exception e) { System.out.println(e); } System.out.println("Hello World!"); } } 运行结果:begin java.lang.ArithmeticException:/by zero end Hello World! 又例:这是异常处理的标准格式,用了5个关键字:throws,throw,try,catch,finally class A { public int div(int x, int y)throws Exception { int t=0; System.out.println("begin"); try { t=x/y; } catch (Exception e) { throw e; } finally{System.out.println("end");} return t; } } class Lesson5 { public static void main(String[] args) { A a=new A(); int m=0; try { m=a.div(2,0); } catch (Exception e) { System.out.println(e); } System.out.println("Hello World!"); } } 运行结果:begin end java.lang.ArithmeticException:/by zero Hello World! 例子的小结:程序先执行了finally语句,再打印出异常。 小结:由throw语句抛出的对象必须是java.lang.Throwable类或者其子类的实例。 throws和throw的区别: 1、 throws在方法声明的地方抛出异常,throws在方法里面抛出异常。 2、 自定义异常类的抛出一定要用throw。 3、 Throws抛出异常,调用方法时必须异常处理。 4、 如果想明确地抛出一个RuntimeException,必须用throws语句来声明它的类型。 5、 程序会在throws语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中,从里向外寻找含有与其匹配的catch字句的try块。 自定义异常 通常采用Exception作为异常类的超类。必须从一个现有的异常类继承,这个父类最好和新定义的异常类近似。 例:class MyException extends Exception { public MyException(String str) {super(str); } } class Lesson6 { public static void main(String[] args) {try { throw new MyException("hahaha"); } catch (MyException e) {System.out.println(e); } } } 运行结果:MyException:hahaha 例:class MyException extends Exception { public MyException(String str) {super(str); } } class Iller { String name; int id; public Iller(String name,int id) { this.name=name; this.id=id; } public void guahao()throws Exception {if(id==0) throw new MyException("sorry,no guahao"); System.out.println("yes"); } } class Lesson7 { public static void main(String[] args) {Iller i=new Iller("zs",1); Iller i=new Iller(“zs”,0); try { i.guahao(); } catch (Exception e) { System.out.println(e); } } } 运行结果:yes MyException: sorry , no guahao 1、 assert关键字(断言) 例: class Lesson9 { public static void main(String[] args) { int x=12; assert x==121; } } 运行:java –ea Lesson9 结果:Exception in thread”main”java.lang.Assertion Error at Lesson9.main(Lesson9.java:6) 小结:用assert关键字后,运行程序时应输入:java –ea 类名 编写程序时应注意的问题: 1、 避免过大的try语句块,不要把不会出现异常的代码放到try块里面,尽量保持一个try块对应一个或多个异常。 2、细化异常的类型,不要不管什么类型的异常都写成Excetpion。 3、catch语句块尽量保持一个块捕获一类异常,不要忽略捕获的异常,捕获到后要么处理,要么重新抛出新类型的异常。 4、不要把自己能处理的异常抛给别人。 垃圾回收机制:finalize()方法 例:class Lesson10 { public static void main(String[] args) { A a=new A(); a.print(); new A().print(); new A().print(); new A().print(); System.gc(); } } class A { public void print() { System.out.println("I am A"); } public void finalize() { System.out.println("I am over"); } } 运行结果:I am A I am A I am A I am A I am over I am over I am over 小结:匿名对象初始化后成为垃圾,用“System.gc( )”进行垃圾回收。 第十一次课 线程、线程同步 线程的概念 1. 进程是指运行中的应用程序,每一个进程都有自己独立的内存空间。对一个应用程序可以同时启动多个进程。例如每次执行JDK的java.exe程序,就启动了一个独立的Java虚拟机进程,该进程的任务是解析并执行Java程序代码。 2. 线程是指进程中的一个执行流程,有时也称为执行情景。一个进程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。当进程内的多个线程同时运行,这种运行方式称为并发运行。 注意:A.一个CPU不能同时执行多个线程,只能执行一个。 B.单进程一旦某个环节出了问题,就不能执行下去了。 线程的两种创建和启动方法 1. 定义一个Thread类的子类,覆盖Thread类的run()方法,然后创建该子类的实例。 2. 定义一个实现Runnable接口的类,实现它的run()方法,然后将这个类的实例作为Thread的构造方法的参数,创建Thread类的实例。 3. 调用start()方法启动线程。 比如:MyThread t = new MyThread(); t.start(); 例程(1) class ST extends Thread //这是一个买票的线程 { int ticket=10; public void run() { for (int i=0;i<30 ;i++ ) { if (ticket>0) System.out.println(getName()+" :"+ticket--); } //Thread类中getName()方法可以用来返回该线程的名字 } }; class lesson1 { public static void main(String[] args) { ST s1=new ST(); ST s2=new ST(); //创建了两个线程对象s1和s2,有20张票 s1.run(); //ran()方法的调用 s2.run(); } } 运行结果: Thread-0 :10 Thread-0 :9 Thread-0 :8 Thread-0 :7 Thread-0 :6 分析:1.线程是程序中的执行程序,Java虚拟机允许 Thread-0 :5 应用程序并发地运行多个执行线程。 Thread-0 :4 2.Thread类中有:public void run() Thread-0 :3 如果该线程是使用独立的Runnable运行对 Thread-0 :2 像构造的,则调用Runnable对象的run方法, Thread-0 :1 否则,该方法不执行任何操作,Thread的子 Thread-1 :10 类应该重写该方法。 Thread-1 :9 3.该程序运行结果表明:一个站点卖完了,第 Thread-1 :8 二个站点再卖,这时候两个线程对象已经建 Thread-1 :7 立起来了。 Thread-1 :6 Thread-1 :5 Thread-1 :4 Thread-1 :3 Thread-1 :2 Thread-1 :1 例程(2) 把例程(1)的运行类改为: class lesson2 { public static void main(String[] args) { ST s1=new ST(); ST s2=new ST(); //用继承Thread类来产生两个线程对象:s1和s2 s1.start(); //start()把线程启动再运行 s2.start(); } } 运行结果: 分析:1.该运行结果是偶然的,可以多执行几次,观 Thread-0 :10 察运行结果的变化 Thread-1 :10 2.该运行结果表明:这样的程序可以实现交替 Thread-0 :9 的买票,但是10张票被卖了20次 Thread-1 :9 3.若要共享10张票,而不是产生20张票,实 Thread-1 :8 现的方法:在ST类中把ticket定义成静态 Thread-1 :7 的。 Thread-1 :6 Thread-1 :5 Thread-1 :4 Thread-1 :3 Thread-1 :2 Thread-1 :1 Thread-0 :8 Thread-0 :7 Thread-0 :6 Thread-0 :5 Thread-0 :4 Thread-0 :3 Thread-0 :2 Thread-0 :1 例程(3) class ST implements Runnable { int ticket=10; public void run() { for (int i=0;i<30 ;i++ ) { if (ticket>0) System.out.println(Thread.currentThread().getName()+" :"+ticket--); //这里不能够直接用getName()方法是因为:该类实现的是Runnable接口,而Runnable中只有run()方法,没有getName()方法,且getName()不是静态的,所以不能够直接调用 } } }; class lesson3 { public static void main(String[] args) { ST s=new ST(); //产生了Runnable接口的一个对象,但是Runnable类中只有run方法,产生不了线程 Thread t1=new Thread(s); //用Thread产生第一个线程 Thread t2=new Thread(s); //用Thread产生第二个线程 t1.start(); //start()是启动线程的方法,会调用run()方法 t2.start(); } } 运行结果:Thread-0 :10 Thread-0 :8 Thread-1 :9 Thread-0 :7 Thread-1 :6 Thread-0 :5 Thread-1 :4 Thread-0 :3 Thread-1 :2 Thread-0 :1 分析:(1)Runnable接口的唯一方法:void run() .该方法用于启动线程,权限是默认的,而Thread类中的run()方法权限是public的。 (2)Thread类中的一个构造方法:public Thread(Runnable target) 该构造方法是通过Thread传一个形参来产生一个线程,并且该形参是一个Runnable接口的对象。 (3)Runnable本身没有构造方法,所以本身不能产生线程,所以要借助Thread类的构造方法来产生线程。 (4)currentThread()方法:返回对当前正在执行的线程对象的应用,可以用该方法来得到线程的名字 例程(4) 把例程(3)的运行类改为: class lesson4 { public static void main(String[] args) { ST s=new ST(); Thread t1=new Thread(s,"station1"); //station1是给线程取的名字 Thread t2=new Thread(s,"station2"); t1.start(); t2.start(); } } 运行结果是:station1 :10 station1 :8 station1 :7 station1 :6 station2 :9 station1 :5 station2 :4 station1 :3 station2 :2 station1 :1 分析:(1)Thread类中的一个构造方法:public(Runnable target,String name) name表示的是线程的名字 (2)运行结果只有十张票,是因为只创建了一个ST对象 (3)Runnable下面有Thread,Runnable又是通过Thread来创建线程,这 是一种代理模式 该程序通过Thread代理,Thread类是Runnable的子类,但其它子类运行也要通过Thread类来运行 (4)该线程存在的不合理:有可能一张票卖给两个人 Runnable与Thread的区别 1. Runnable能够实现多个接口 2. Runnable可资源共享 3. Thread类继承Object,实现Runnable接口 4. 编写程序时,尽量用Runnable来实现多线程的操作 四.sleep()方法的使用 例程(1) class ST implements Runnable { int ticket=10; public void run()throws Exception { for (int i=0;i<30 ;i++ ) { if (ticket>0) { Thread.sleep(100); //表示停100ms System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } } }; class lesson5 { public static void main(String[] args) throws Exception { ST s=new ST(); Thread t1=new Thread(s,"station1"); Thread t2=new Thread(s,"station2"); t1.start(); t2.start(); } } 运行结果:编译出错 分析:(1)在API文档中:public static void sleep(long millis) throws InteruptedException 在API文档中,只要用到一个方法后面有抛出异常的,就要进行异常的捕捉或处理,无论有没有发生异常 (2)例程(1)对异常的处理是错误的:因为Runnable中的run()方法是没有抛出异常的,ST中的run()是对Runnable中的run()方法进行重写的,而子类重写父亲的方法,不能抛出比父类更多的异常 例程(2) class ST implements Runnable { int ticket=10; public void run() { for (int i=0;i<30 ;i++ ) { if (ticket>0) { try {Thread.sleep(100); //静态的方法可以直接类名.方法名进行调用 } catch (Exception e) {} //对异常不进行处理 System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } } }; class lesson6 { public static void main(String[] args) { ST s=new ST(); Thread t1=new Thread(s,"station1"); Thread t2=new Thread(s,"station2"); t1.start(); t2.start(); } } 运行结果:station1 :10 station2 :9 station2 :8 station1 :8 station1 :7 station2 :6 station1 :5 station2 :4 station1 :3 station2 :2 station1 :1 station2 :0 分析:(1)该运行结果是随机的,运行多次的结果可能是不一样的 (2)运行结果中出现了两个票号为8的,还出现了票号为0的 不正常的原因:判断和出票之间休息了100ms,休息的时候,其它线程启动,也进行判断,即在票还没有卖出的时候其它进程也进来了 (3)该程序尽管不加上Thread.sleep(100ms);程序也会出现不正常的情况,加上Thread sleep(100ms);只是为了更明显的表现出问题 线程同步 1. 问题产生的原因:有了延迟操作 2. 解决方法:保持操作的原子性(加锁:通过同步操作) 3. 同步的两种方法: 同步代码块:synchronized,要注意锁住的一般是当前对象:this 同步方法 同步代码块实现同步的方法的举例: 例程(1) class ST implements Runnable { int ticket=10; String str=new String("h"); public void run() { for (int i=0;i<30 ;i++ ) { synchronized(str) //str称为:锁旗标或监视器 {if (ticket>0) { try {Thread.sleep(100); } catch (Exception e){} System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } } } }; class lesson7 { public static void main(String[] args) { ST s=new ST(); Thread t1=new Thread(s,"station1"); Thread t2=new Thread(s,"station2"); t1.start(); t2.start(); } } 运行结果:station2 :10 station2 :9 station2 :8 station2 :7 station1 :6 station1 :5 station1 :4 station2 :3 station2 :2 station2 :1 分析:(1)监视器str可以是任意的对象 (2)运行的结果是正确的,但是速度比较慢,原因是:Thread.sleep(100),等待了100ms;程序每次运行都要检查锁旗标 (3)锁旗标(监视器)一般有两种状态:0和1 一个线程进行判断,若str的值为1,则得到这把锁,程序可以往下进行,在运行的时候,会把str的值改为0,表示其它线程也想要得到这把锁,也想运行时,只能等待,不能执行 同步方法实现线程同步举例 例程(2) class ST implements Runnable { int ticket=10; String str=new String("h"); public void run() { for (int i=0;i<30 ;i++ ) this.sale(); } public synchronized void sale() //买票的方法,加上synchronized,该方法就同步 { if (ticket>0) { try {Thread.sleep(100); } catch (Exception e){} System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } }; class lesson8 { public static void main(String[] args) { ST s=new ST(); Thread t1=new Thread(s,"station1"); Thread t2=new Thread(s,"station2"); t1.start(); t2.start(); } } 运行结果:station2 :10 station2 :9 station2 :8 station2 :7 station2 :6 station1 :5 station1 :4 station1 :3 station1 :2 station1 :1 分析:程序运行结果正常,说明同步方法也能实现线程同步 测试同步方法和同步代码块用到的锁旗标(监视器)是否是同一个 例程(3) class ST implements Runnable { int ticket=10; String str=new String("h"); public void run() { if(str=="huang") { for (int i=0;i<30 ;i++ ) this.sale(); } else { for (int i=0;i<30 ;i++ ) synchronized(this) { if (ticket>0) { try {Thread.sleep(100); } catch (Exception e){} System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } } } public synchronized void sale() { if (ticket>0) { try { Thread.sleep(100); } catch (Exception e){} System.out.println("sale()"); System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } }; class lesson9 { public static void main(String[] args) throws Exception { ST s=new ST(); Thread t1=new Thread(s,"station1"); Thread t2=new Thread(s,"station2"); t1.start(); s.str="huang"; Thread.sleep(100); t2.start(); } } 运行结果:sale() Station1 :10 sale() station1 :9 sale() station2 :8 sale() station1 :7 sale() station2 :6 sale() station1 :5 sale() station2 :4 sale() station1 :3 sale() station2 :2 sale() station1 :1 分析:(1)此时程序是不安全的,仍然可能出现票号为0 (2)运行结果表明都是执行同步方法里面的内容,这是因为:线程t1启动之后并不是马上执行,只是准备执行,当准备执行的时候,str里面的内容已经改变了,即程序中IF判断的结果改变了,所以之后执行的都是同步方法里面的内容 例程(4) 把例程(3)的运行类改为: class lesson10 { public static void main(String[] args) throws Exception { ST s=new ST(); Thread t1=new Thread(s,"station1"); Thread t2=new Thread(s,"station2"); t1.start(); Thread.sleep(100); s.str="huang"; t2.start(); } } 运行结果:station1 :10 sale() station2 :9 station1 :8 sale() station2 :7 station1 :6 sale() station2 :5 station1 :4 sale() station2 :3 station1 :2 sale() station2 :1 station1 :0 分析:(1)运行结果说明了线程不同步 (2)造成线程不同步的原因:加锁的对象不同,即同步代码块和同步方法的锁旗标(监视器)不是同一个。同步代码块用到的对象是:str,同步方法用到的对象是:this (3)此时,实现线程同步的方法:把同步代码块和同步方法的锁旗标(监视器)改成一样的 死锁 1. 死锁是程序运行时发生的一种状态 2. 产生原因:多个线程共享同一资源时,要进行加锁操作(同步),但是,过多的同步会造成死锁 死锁程序的模拟: class ST implements Runnable { int ticket=10; String str=new String("h"); public void run () { if(str.equals("huang")) { for (int i=0;i<30 ;i++ ) this.sale(); } else { for (int i=0;i<30 ;i++ ) synchronized(str) //加了对象为str的锁 { if (ticket>0) { try {Thread.sleep(100); } catch (Exception e) {} synchronized(this){} //加了对象为this的锁 System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } } } public synchronized void sale() //加了对象为this的锁 { if (ticket>0) { try { Thread.sleep(100); } catch (Exception e) {} System.out.println("sale() "); synchronized(str){} //加了对象为str的锁 System.out.println(Thread.currentThread().getName()+" :"+ticket--); } } }; class lesson11 { public static void main(String[] args) throws Exception { ST s=new ST(); Thread t=new Thread(s,"station1"); Thread t1=new Thread(s,"station2"); t.start(); Thread.sleep(100); s.str="huang"; t1.start(); } } 运行结果:station1 :10 sale() 分析:(1)运行结果产生的是死锁,程序运行不下去了,但是程序执行的结果也可能不是产生死锁,而是完整的执行完毕。程序此时是不同步的,因为用到的不是同一个锁旗标(监视器) (2)两个同步交叉执行时才会出现死锁 (3)该程序产生死锁的原因:同步代码块占有了一个资源,还需要另一资源,而另一资源是同步方法占有的资源;而同步方法占有了自己的资源之后,还需要再占有同步代码块的资源,产生了交叉。 第十二次课 进程通信 后台线程 后台线程:指为其他提供服务的线程,也叫守护线程。 用thread类的setDaemon(true)方法,就能把一个线程设置为后台线程。 后台线程的特点: 后台线程与前台线程相伴相随,只有所有前台线程都结束生命周期,后台线程才会结束周期。只要有一个前台线程还没有运行结束,后台线程就不会结束生命周期。 例:class Lesson1 { public static void main(String[] args) { A a=new A(); a.start(); System.out.println("main()"); } } class A extends Thread {public void run() { while(true) {System.out.println("A.run"+getName()); } } } 运行结果:A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 …… 分析:当按下ctrl+c时,才会中断线程,因为该线程是前台线程。若线程为后台线程,则会自动结束。 例:class Lesson1 { public static void main(String[] args) { A a=new A(); a.setDaemon(true); a.start(); System.out.println("main()"); } } class A extends Thread {public void run() { while(true) {System.out.println("A.run"+getName()); } } } 运行结果:A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 注意:只有在线程启动前(即调用start()方法以前),才能把它设置为后台线程。否则,将会导致IllegalThreadStateException异常。 join()方法 当前运行的线程可以调用另一个线程的join()方法,当前运行的线程将转到阻塞状态,直到另一个线程运行结束,它才会恢复运行。 join()有两种重载形式: 1、 public void join() 2、 public void join(long timeout) timeout用于设定当前线程被阻塞的时间。 例:class Lesson3 { public static void main(String[] args)throws Exception { A a=new A(); a.setDaemon(true); a.start(); while(true) { a.join(1000); //让主线程阻塞1000ms(即1s) try{ Thread.sleep(500); } catch(Exception e){} System.out.println("main():"); } } } class A extends Thread {public void run() {while(true) {System.out.println("A.run()"+getName()); try{ Thread.sleep(500); } catch(Exception e) {} } } } 运行结果:A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 main(): A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 main(): A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 main(): …… 线程的优先级 优先级高的线程获得较多的运行机会,优先级低的线程获得较少的运行机会。Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。 最高优先级:MAX_PRIORITY,取值为10 默认优先级:NORM_PRIORITY,取值为5 最低优先级:MIN_PRIORITY,取值为1 注意:主方法优先级默认为NORM_PRIORITY 例:class Lesson4 { public static void main(String[] args) { A a=new A(); A a1=new A(); A a2=new A(); a.setPriority(Thread.MAX_PRIORITY); a.start(); a1.start(); a2.start(); System.out.println(Thread.MAX_PRIORITY); System.out.println(Thread.NORM_PRIORITY); System.out.println(Thread.MIN_PRIORITY); } } class A extends Thread {public void run() {for(int i=0;i<5;i++) {System.out.println("A.run"+getName()); } } } 运行结果:10 5 1 A.run()Thread-0 A.run()Thread-0 A.run()Thread-2 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-0 A.run()Thread-2 A.run()Thread-2 A.run()Thread-2 A.run()Thread-1 A.run()Thread-1 A.run()Thread-1 A.run()Thread-1 线程的通信 wait():执行该方法的线程释放对象的锁,Java虚拟机把该线程放在该对象的等待池中,转换为就绪状态。该线程等待其他线程将它唤醒。 Sleep():执行该方法会使当前进程转换为阻塞状态,但不会释放锁。并且进程会自动苏醒,不用其他进程唤醒。 notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程。Java虚拟机从对象的等待池中随机选择一个线程,把它转到对象的锁池中。 例:生产者—消费者问题 class Lesson6 { public static void main(String[] args) { LikeStack l=new LikeStack(); Producer p=new Producer(l); Consumer c=new Consumer(l); new Thread(p).start(); new Thread(c).start(); } } class Szp { int id; public Szp(int id){this.id=id;} public String toString(){ return "shanzhapian :"+id;} } class LikeStack { Szp sa[]=new Szp[5]; int top=0; public synchronized void push(Szp s){ this.notify(); /*if*/while(top==sa.length) { try { this.wait(); } catch (Exception e) { } } sa[top]=s; top++; } public synchronized Szp pop(){ /*if*/while (top==0) { try { this.wait(); } catch (Exception e) { } } this.notify(); top--; return sa[top]; } } class Producer implements Runnable { LikeStack ls=null; public Producer(LikeStack ls){this.ls=ls;} public void run() { for (int i=0;i<20 ;i++ ) { Szp sz=new Szp(i); ls.push(sz); System.out.println("shengchan : "+sz); try { Thread.sleep(500); } catch (Exception e) { } } } } class Consumer implements Runnable { LikeStack ls=null; public Consumer(LikeStack ls){this.ls=ls;} public void run() { for (int i=0;i<20 ;i++ ) { Szp sz=ls.pop(); System.out.println("chile :"+sz); try { Thread.sleep(500); } catch (Exception e) { } } } } 运行结果: shengchan:shanzhapian:0 chile:shanzhapian:0 shengchan:shanzhapian:1 chile:shanzhapian:1 shengchan:shanzhapian:2 chile:shanzhapian:2 …… shengchan:shanzhapian:18 chile:shanzhapian:18 shengchan:shanzhapian:19 chile:shanzhapian:19 但是在不同的机器上运行会产生不同的结果,可能与系统的配置有关。 第十三次课 集合 集合的概念:集合就是若干用途,性质相同或相近的“数据”组合而成的一个整体。 集合的相关API关系结构: 集合类型 集(Set):不区分元素的顺序,不能出现重复元素 列表(List):区分元素的顺序,能出现重复元素 映射(Map):保存成对的“键-值”(Key-Value)信息,不能包含重复的键,每个键最多只能映射一个值。 Java集合中只能保存引用类型的数据,实质上存放的是对象的引用,而非对象本身,集合中元素相当于引用类型变量。 Collection接口 Collection接口:描述Set和List集合类型的根接口。 方法: boolean add(Object o) void clear() boolean contains(Object o) boolean isEmpty() Iterator iterator() boolean remove(Object o) int size() Object[] toArray() Set和List接口 Set和List接口:分别描述前述的集和列表结构,二者均为Collection子接口。 方法: void add(int index,Object element) Object get (int index) Object set(int index,Object element) int indexOf (object o) Object remove(int index) Map接口 Map接口:描述了映射结构,Map结构允许以键集,值集合或键-值映射关系集的形式查看某个映射的内容。 方法:Object put (Object key, Object value) Object get(Object key) boolean isEmpty() int size() void clear() boolean containsKey(Object key) boolean containsValue (Object value) Set keySet() Collection values() ArrayList ArrayList :实现了List接口,用于表达长度可变的数组列表。ArrayList列表允许元素取值为null。除实现了List接口定义的所有功能外,还提供了一些方法来操作列表容量的大小。 方法: public ArrayList() public ArrayList(int initialCapacity) public void ensureCapacity(int minCapacity) public void trimToSize() 用法举例: import java.util.*; class TestArrayList { public static void main(String[] args) { ArrayList h=new ArrayList(); h.add("huang"); h.add("guo"); h.add(new Integer(3)); h.add(new Double(3.0)); h.add("guo"); //System.out.println(h.add(new Integer(3))); System.out.println(h); System.out.println(h.size()); for (int i=0;i
本文档为【JAVA程序设计课堂笔记整理java课堂笔记】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_200383
暂无简介~
格式:doc
大小:556KB
软件:Word
页数:78
分类:互联网
上传时间:2018-09-09
浏览量:53