Java作业

第四章

1.名词解释:构造方法、抽象。
解:构造方法:构造方法是一个与类名相同的方法。
抽象:从被研究对象中舍弃个别的、非本质的或与研究主旨无关的次要特征,而抽取与研究有关的共性内容加以考察,形成对研究问题正确、简明扼要的认识。

2.对象位于内存何处?
解:堆。
声明能引用对象的实质是什么?
解:声明就像一个指针,指向对象的地址,就好比对象的名片。

3.对象和基本数据类型作为参数传递时,有什么不同?
解:基本数据类型作为参数在方法中的传递是值传递;而对象是引用传递,当对象作为参数传递时,传递的对象是地址。

4.在自定义对象中写finalize方法,看看什么情况下finalize被调用。
解:当类的对象被当成垃圾释放掉时,调用这个方法。

5.对象在什么条件下成为垃圾?
解:当对象没有任何引用时,成为垃圾。
什么情况下释放垃圾对象?
解:当系统资源不够或“提醒”系统释放垃圾时,才释放垃圾对象。
如何证明一个对象被释放了?
解:当finalize方法被调用时,对象就被释放了。

6.final修饰符都有什么作用?
解:修饰属性时,该属性为常量。修饰方法时,该方法为最终方法,在子类中不能被覆盖。

7.static修饰的属性和方法有什么特点?
解:用static修饰符修饰的域变量不属于任何一个类的具体对象,而专属于类。其特点为:它被保存在类的内存区(堆中)的公共存储单元中,而不是保存在某个对象的内存区中。用static修饰符修饰的方法称为静态方法,它属于类方法,不属于类的任何对象。static方法是类方法,但可以被所有对象所访问。static方法内部的代码,只能访问类中的static属性或方法,不能访问类中的非static属性或方法。main方法是特殊的静态方法。

8.Application程序执行时,为什么不能带后缀名?
解:Java命令是执行一个类。

9.下面代码中,Vector是Java.util包中的一个类,关于此类哪个叙述是正确的?()

public void create(){
Vector myVect;
myVect=new Vector();
}

A.第二行的命令不会为变量myVect分配内存空间。
B.第二行的声明分配了一个Vector对象内存空间。
C.第二行语句创建一个Vector类对象。
D.第三行语句创建一个Vector类对象。
E.第三行语句为一个Vector类对象分配内存空间。
解:DE

第五章

1.面向对象的主要特征是什么?
解:封装、继承、多态。

2.封装是如何实现的?
解:封装是利用访问控制符来实现的。封装就是利用抽象数据类型(类)将数据和基于数据的操作绑定在一起,数据被保存在抽象数据类型内部,系统只有通过被授权的操作方法才能够访问数据。其特点为:1.数据和基于数据的操作方法构成一个统一体。2.类的操作方法实现细节被隐藏起来,只是通过操作接口名称进行调用,操作内部的变动不会影响接口的使用。

3.对象之间如何相互作用?作用的条件是什么?
解:对象之间通过组合,对对象内部的属性引用来实现。条件:A对象对B对象的引用是建立在B对象的授权基础上的,B对象私有的属性和私有方法A对象是无法访问的。

4.protected修饰符有何特点?
解:当类前修饰符为public时,当属性和方法前的修饰符为protected时,在类定义层面上,访问权限为包中的类和所有子类,而在对象层面上,则只包含包中的类。当类前的修饰符为默认时,当属性和方法前的修饰符为protected时,不论是类定义还是对象引用的范围都只包含包中的类。

5.Object都有哪些方法?
在这里插入图片描述

6.重载的方法之间一般有什么关系?
解:重载的多个方法之间往往存在一定的调用关系,即一个方法写有实现功能,其他方法采用委托方式进行调用——体现了程序共享的设计思想。

7.子类覆盖父类方法需要什么条件?子类中定义与父类同名的方法一定是覆盖吗?
解:条件:方法的参数、返回类型、方法名要相同,子类的访问修饰符权限应等于或大于父类。子类中定义与父类同名的方法不一定是覆盖,如果子类定义的方法与父类名称相同(大小写完全匹配),但参数名称不同,不是覆盖,而是重载。如果名称、参数相同,返回值不同,则编译不能通过。

8.封装、继承与多态在面向对象程序设计中的用途是什么?
解:
封装:封装使面向对象程序设计具有“高内聚,松耦合”的特点。让数据和基于数据的操作方法构成一个统一体。类的操作方法实现细节被隐藏起来,只是通过操作接口名称进行调用,操作内部的变动不会影响接口的使用。
继承:1.继承是面向对象程序设计中对功能进行复用的重要手段。面向对象应用程序经常以框架和中间件为基础进行设计,应用程序代码和框架代码、中间件代码能够进行融合的主要方式就是采用继承,也就是应用代码中的类继承框架或中间件指定的类,便拥有了框架或中间件的所有功能。2.继承为引用带来了新特点。使用继承机制,一般类可派生出特殊类,原先发往一般类对象的消息也由于继承机制的原因也可发向特殊类对象,这就为引用带来了新的特点:父类或抽象类的声明可引用所有子类或具体类对象并且在运行时刻可以进行动态替换。
多态:面向对象程序设计过程中,对于能进行消息处理的接口方法,有时既需要对其功能进行复用,同时又需要对其进行扩充(补充新的参数),重载正好能满足这种要求,因为旧的接口方法得以保留以保障原先使用程序的稳定,同时又可增加带参数的新的重载方法以满足扩充需求,并且新增加的重载方法与原先旧方法之间存在功能复用关系;而方法覆盖与引用替换结合,可使抽象类的声明在保证消息发送统一性的前提下,具有消息结果执行上的相异性特点。

9.设计Src和Dis两个类,Src中有一个被封装的属性,类型为int(要求为非负值),每当通过特定方法更改Src对象中的这个属性后,Dis对象都能得到通知,并向Src发消息获得此属性值。
解:

import java.util.*;
class Src{
	private int a=0;
	public boolean change(int _a) {//修改a属性的方法,只有当值大于0时,a才会被修改。
		if(_a<0) {return false;}
	else {a=_a;return true;}
	}
	public int access() {
		return a;
	}
}
 class Dis{
	 private int b=0;
	 public void get_information(Src s) {//获得Src类中a的值。
		 b=s.access();
	 }
	 public void speak() {
		 System.out.println("b="+b);
	 }
 }
public class test {
    public static void main(String[] args) {
    	Src src=new Src();
    	Dis dis=new Dis();
    	System.out.println("a="+src.access());
    	dis.speak();
    	Scanner input = new Scanner(System.in);
    	int _a = input.nextInt();
    	if(src.change(_a)) {dis.get_information(src);}//只有当Src类中的属性值被修改后,Dis对象才会得到通知,并向Src对象发送消息获得此属性值。
    	System.out.println("a="+src.access());
    	dis.speak();
    }
}

输出:
a=0
b=0
输入:5
输出:
a=5
b=5

第六章

1.this和super各有几种用法?
解:this的用法有3种:(1)this.域变量、this.成员方法。(2)this(参数)——引用重载的构造方法。(3)this指代当前对象。
super的用法有2种:(1)super.域变量、super.成员方法(参数)。(2)super(参数)。

2.子类对象实例化的具体过程是什么?
解:子类对象实例化的步骤:(1)为子类对象分配内存空间,对域变量进行默认初始化。(2)绑定构造方法,将new对象中的参数传递给构造方法的形式参数。(3)调用this或super语句,注意二者必居其一,但不能同时存在。(4)进行实例变量的显式初始化操作。(5)执行当前构造方法体中的程序代码。

3.类的域变量和方法中定义的局部变量在初始化上有何区别?
解:类的域变量在类初始化的时候就开始创建了,不用显示初始化;而方法中的变量是在调用到该方法时,才会为该变量创建,必须显示初始化。

4.模仿形成抽象类的过程,自选角度,形成一个自己的抽象类,并在程序的类继承和引用中体现抽象类的作用。
解:

abstract class washer{
	abstract void speak();
}
 class rose extends washer{
	 void speak() {
		 System.out.println("I am rose brand washer.");
	 }
 }
 class huipu extends washer{
	 void speak() {
		 System.out.println("I am huipu brand washer.");
	 }
 }
public class test {
    public static void main(String[] args) {
    	washer t1=new rose();
    	washer t2=new huipu();
    	t1.speak();
    	t2.speak();
    }
}

输出结果:
I am rose brand washer.
I am huipu brand washer.

5.接口有什么作用?自己定义一个接口,并给出实现类和使用类。
解:程序设计中,功能的实现和功能的使用是不可分的两个方面。当功能没有实现和使用前,先定出接口,再进行功能的实现以及使用,可使功能的实现和使用以弱耦合的方式连接起来。使用者按照接口使用,实现者按照接口实现,当实现者内部发生变化时,只要接口不发生变化,使用者就不必更改其代码。从这个意义上讲,接口就相当于一种标准,类似于产品功能说明书。

interface Washer{                           //定义接口:洗衣机都有哪些功能?
	public abstract void startUp();         //启动
	public abstract void letWaterIn();      //进水
	public abstract void washClothes();     //洗衣
	public abstract void letWaterOut();     //排水
	public abstract void stop();            //停止
}
//实现接口:假定有一个叫玫瑰牌的洗衣机,实现了所有接口,而且自己还独有一项功能叫“脱水”。
class RoseBrand implements Washer{
	public void startUp() {System.out.println("startUp");}
	public void letWaterIn() {System.out.println("letWaterIn");}
	public void washClothes() {System.out.println("washClothes");}
	public void letWaterOut() {System.out.println("letWaterOut");}
	public void stop() {System.out.println("stop");}
	public void dehydrate() {System.out.println("dehydrate");}//脱水
}
//使用接口
public class test {
    public static void main(String[] args) {
    	//接口声明引用实现接口的RoseBrand类的对象
    	Washer w=new RoseBrand();
    	w.startUp();
    	w.letWaterIn();
    	w.washClothes();
    	w.letWaterOut();
    	w.stop();
    	//当通过接口调用玫瑰牌洗衣机类独有的功能方法,编译会报错
    	//w.dehydrate();
    }
} 

输出结果:
startUp
letWaterIn
washClothes
letWaterOut
stop

6.抽象类与接口的异同点是什么?
解:在这里插入图片描述
7.引用比较方法有哪些?
解:(1)equals方法比较。equals是object的方法,因此所有类对象都可以利用它进行引用比较,判断是否指向同一对象。(2)使用“= =” 进行比较。如果 “==”两边是对象引用,则比较的是它们的引用是否相同;如果两边是数值,则比较的是他们的值(如果值类型不同,有可能发生类型转化,例如10= =10.0将返回true);如果一边是引用,一边是值,则编译错误。(3)使用instanceof比较引用类型。运算符的格式为:“a instanceof A”,其中a为对象的引用,A为类。如果a为A的实例或A子类的实例,则返回true;如果a为A父类的实例,则返回false;如果a对象的类和A没有任何关系,则编译不会通过。

8.内部类的作用是什么?什么情况下使用匿名内部类?
解:内部类可以直接访问外部类中的所有属性,包括修饰符为private的属性或方法,因此如果需要将一个类中的一些属性对其他类进行封装,而只对一个类开放时(类似于C++的友元概念),则应当想到应用内部类。
匿名内部类就是在类中需要实例化这个类的地方(通常为方法内),定义一个没有名称的类。匿名内部类的使用规则:(1)匿名内部类不能有构造方法,但是如果这个匿名内部类继承了一个只含有带参数构造方法的父类,在创建它的对象的时候,在括号中必须带上这些参数。(2)匿名内部类不能定义任何静态成员和方法。(3)匿名内部类不能被public、protected、private、static修饰。(4)只能创建匿名内部类的一个实例。匿名内部类的使用条件:(1)只用到类的一个实例。(2)类在定义后马上用到。(3)类非常小。

9.不上机,判断下面程序的输出结果。

class X{
	Y b=new Y();
	X(){
		System.out.println("X");
	}
}
class Y{
	Y(){
		System.out.println("Y");
	}
}
public class Z extends X{
	Y y=new Y();
	Z(){
		System.out.println("Z");
	}
	public static void main(String[] args) {
		new Z();
	}
}

输出结果:YXYZ

10.什么是数据隐藏?如何证明子类对父类同名方法进行重新定义,只能是方法的覆盖,而不是方法的隐藏?
解:数据隐藏是父类与子类同名的数据成员在子类中会被隐藏,即“看不见”,调用时用的是子类的数据成员;但父类的数据成员在子类中仍然初始化并且存在,可以用super.数据成员来调用。父类与子类同名的方法在子类中是不存在的,是被覆盖掉的,因为super.父类方法是不合法的。并且用父类的引用去调用子类的对象的方法时,调用的是子类自己的方法,而不是父类的方法,这可以证明方法是被覆盖掉的,而非隐藏。

11.A1、A2分别是具体类A的子类,A3为A1的子类,A1、A2之间的关系为平行类。下面的代码为连续的程序片段,请问哪些是正确的?(标记文本为正确)
A a=new A();
a=new A1();
a=new A2();
a=new A3();
A1 a1=new A3();
A3 a3=a1;
A2 a2=new A1();
a3=new A2();

12.借助JDK帮助,编写程序实现这样的功能:Applet当中的TextFiled,每输入任一字符,在一个label当中都能动态跟踪刷新。
解:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class MyApplet1 extends Applet implements ActionListener{ 
    private TextField input;
    private String d;
    //进行初始化工作,产生对象,加入监听者
    public void init(){
        input = new TextField(10);
        //myApplet是容器,input是组件,调用add使input嵌入容器
        add(input); 
        input.addActionListener(this); //向TextField注册监听器
    }
    public void paint(Graphics g){
        g.drawString("您输入了字符:"+d,10,50);
    }
    public void actionPerformed(ActionEvent e) {
        d=input.getText();
        //进行刷新,调用paint()方法
        repaint();
    }   
}

输出结果:
在这里插入图片描述
在这里插入图片描述

第七章

1.“程序中凡是可能出现异常的地方必须进行捕获或抛出”,这句话对吗?
解:对。程序中的异常必须处理。处理的方式包括捕获和抛出。RuntimeException异常类型虽然不需要显示声明,但也是一种隐式声明抛出。

2.自定义一个异常类,并在程序中主动产生这个异常类对象。
解:

package test;

public class SelfGenerateException extends Exception{

	SelfGenerateException(String msg){
		super(msg);
	}
	static void throwOne() throws SelfGenerateException{
		int a=1;
		if(a==1) {
			throw new SelfGenerateException("a为1");
		}
	}
	public static void main(String[] args) {
		try {
			throwOne();
		}
		catch(SelfGenerateException e){
			e.printStackTrace();
		}
	}
}

输出结果:
test.SelfGenerateException: a为1
at test/test.SelfGenerateException.throwOne(SelfGenerateException.java:11)
at test/test.SelfGenerateException.main(SelfGenerateException.java:16)

3.借助JDK帮助,请列举发生NullPointerException异常的一些情况。
解:当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括:

调用 null 对象的实例方法。
访问或修改 null 对象的字段。
将 null 作为一个数组,获得其长度。
将 null 作为一个数组,访问或修改其时间片。
将 null 作为 Throwable 值抛出。
应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。

4.不执行程序,指出下面程序的输出结果;如果将黑体代码去掉,写出输出结果;如果再将斜体代码去掉,写出输出结果。

public class Test{
    public static void aMethod() throws Exception{
    try{
        throw new Exception();
        }
    **catch(Exception e){
        System.out.println("exception000");
        }**
    *finally{
        System.out.println("finally111");
        }*
    }
    public static void main(String[] args){
        try{
            aMethod();
            }
        catch(Exception e){
            System.out.println("exception");
            }
                System.out.println("finished");
}
}

解:输出依次为:
exception000
finally111
finished

finally111
exception
finished

exception
finished

5.不执行程序,指出下面程序的输出结果。

public class Test{
    public static String output=" ";
    public static void foo(int i){
        try{
            if(i==1){throw new Exception();}
            output+=1;
            }
        catch(Exception e){
            output+="2";
            return;
            }
        finally{output+="3";}
        output+="4";
        }
    public static void main(String[] args){
        foo(0);
        foo(1);
        System.out.println(Test.output);
        }
    }

解:
134234

6.编写一个程序方法,对空指针异常、除数为零异常给出出错的中文提示。当有新异常发生时,可扩展该方法中的代码进行统一处理。
解:

package test;
class Test{
	int a;
}
public class SelfGenerateException {
	
	static void throwOne(){
		try{
			int a=1/0;
		}
		catch(ArithmeticException e){
			System.out.println("除数不能为0!");
		}
	}
	static void throwTwo() {
		try {
			Test t1 = null;
			System.out.println(t1.a);
		}
		catch(NullPointerException e) {
			System.out.println("发生空指针异常!");
		}
	}
	public static void main(String[] args) {
		throwOne();
		throwTwo();
}}

输出:
除数不能为0!
发生空指针异常!

7.从屏幕输入10个数,在输入错误的情况下,给出相应的提示,并继续输入。在输入完成的情况下,找到最大最小数。
解:

package test;
import java.util.*;
public class Test{
	public static void main(String[] args) {
		double[] a=new double[10];
		Scanner s=new Scanner(System.in);
		for(int i=0;i<10;i++) {
			try {
				a[i]=s.nextDouble();
			}
			catch(InputMismatchException e) {
				String str=s.nextLine();
				System.out.println("错误输入:"+str+'\t'+"请您重新输入!");
				i--;
			}
		finally{}
			
	}
		double max=a[0];
	    double min=a[0];
	    for(int i=0;i<10;i++) {
		    if(a[i]>max) max=a[i];
	}
	    for(int i=0;i<10;i++) {
	    	if(a[i]<min) min=a[i];
	    }
	    System.out.println("最大值是:"+max+'\n'+"最小值是:"+min);
	    s.close();
}
}

测试样例:
58
65
64
25
65
98
65
25
nihao
错误输入:nihao 请您重新输入!
zaiganma
错误输入:zaiganma 请您重新输入!
45
woqu
错误输入:woqu 请您重新输入!
12
最大值是:98.0
最小值是:12.0

8.阅读下面的程序,TimedOutException为自定义异常,完成指定方法后面的部分。

public void method()____
{ success=connect();
  if (success==-1){
      throw new TimedOutException();
  }
}

解:
空格部分填写:throws TimedOutException

第八章

3.String类型有什么特点?
解:String的特点是一旦赋值,便不能更改其指向的字符对象。如果更改,则会指向一个新的字符对象。

4.String什么时候进行值比较,什么时候进行引用比较?
解:
值比较:

package test;

public class test {
public static void main(String[] args) {
	String s=new String("Hello");
	String t=new String("Hello");
	if(s.equals(t)) {
		System.out.println("相等");
	}
	else {
		System.out.println("不相等");
	}
}
}

输出:相等
equals是值比较,但却严格区分大小写,如果要忽略大小写比较,则应调用方法eaualsIgnoreCase。

引用比较:

package test;

public class test {
public static void main(String[] args) {
	String s=new String("Hello");
	String t=new String("Hello");
	if(s==t) {
		System.out.println("相等");
	}
	else {
		System.out.println("不相等");
	}
}
}

输出:不相等
原因是s==t比较的是内存中的引用地址。

5.String与StringBuffer的区别是什么?如何相互转化?
解:String一旦赋值,便不能更改其指向的字符对象。如果更改,则会指向一个新的字符对象;而StringBuffer对象可以调用其方法动态地进行增加、插入、修改和删除操作,且不用像数组那样事先指定大小,从而实现多次插入字符,一次整体取出的效果,因而操作字符串灵活方便。
转化:StringBuffer的构造方法可以将一个String对象转化为StringBuffer,而其方法toString()可将一个StringBuffer转化成一个String对象。
如:

String s=new String("Hello);
StringBuffer t=new StringBuffer(s);
String ss=t.toString();

借助JDK,查看String与StringBuffer的常用API,编写实例测试API的功能。
解:

String str = "abc";

is equivalent to:

char data[] = {'a', 'b', 'c'};
String str = new String(data);

Here are some more examples of how strings can be used:

package test;

public class test {
public static void main(String[] args) {
	System.out.println("abc");
    String cde = "cde";
    System.out.println("abc" + cde);
    String c = "abc".substring(2,3);
    String d = cde.substring(1, 2);
    System.out.println(c);
    System.out.println(d);
}
}

输出:
abc
abccde
c
d
public String substring(int beginIndex,
int endIndex)
Returns a string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.

String(StringBuffer buffer)
Allocates a new string that contains the sequence of characters currently contained in the string buffer argument.

package test;

public class test {
public static void main(String[] args) {
	StringBuffer s=new StringBuffer("abc");
	System.out.println(s);
	String t=new String(s);
	System.out.println(t);
}
}

输出:
abc
abc

public char charAt(int index)
Returns the char value at the specified index. An index ranges from 0 to length() - 1. The first char value of the sequence is at index 0, the next at index 1, and so on, as for array indexing.
If the char value specified by the index is a surrogate, the surrogate value is returned.

package test;

public class test {
public static void main(String[] args) {
	String s=new String("abc");
	System.out.println(s.charAt(1));
}
}

输出:b

public void getChars(int srcBegin,
int srcEnd,
char[] dst,
int dstBegin)
Copies characters from this string into the destination character array.
The first character to be copied is at index srcBegin; the last character to be copied is at index srcEnd-1 (thus the total number of characters to be copied is srcEnd-srcBegin). The characters are copied into the subarray of dst starting at index dstBegin and ending at index:

 dstBegin + (srcEnd-srcBegin) - 1
package test;

public class test {
public static void main(String[] args) {
	String s=new String("absihdshdjsc");
	char[] c= {'a','b','c','d','e','f','g'};
	s.getChars(2, 7, c, 1);
	System.out.println(c);
}
}

输出:asihdsg

StringBuffer()
Constructs a string buffer with no characters in it and an initial capacity of 16 characters.
StringBuffer(String str)
Constructs a string buffer initialized to the contents of the specified string.

package test;

public class test {
public static void main(String[] args) {
	StringBuffer s=new StringBuffer();
	String t="abc";
	StringBuffer ss=new StringBuffer(t);
	System.out.println(s);
	System.out.println(ss);
}
}

输出:

abc

StringBuffer append(char c)
Appends the string representation of the char argument to this sequence.
StringBuffer append(char[] str)
Appends the string representation of the char array argument to this sequence.

package test;

public class test {
public static void main(String[] args) {
	StringBuffer s=new StringBuffer();
	char c='a';
	char cc[]= {'b','c','d'};
	s.append(c).append(cc);
	System.out.println(s);
}
}

输出:abcd

public int length()
Returns the length (character count).

package test;

public class test {
public static void main(String[] args) {
	StringBuffer s=new StringBuffer();
	char c='a';
	char cc[]= {'b','c','d'};
	s.append(c).append(cc);
	System.out.println(s.length());
}
}

输出:4

第九章

1.线程和进程的联系和区别是什么?
解:线程是程序执行中的单个的顺序流程;进程是一个执行中的程序,是操作系统对其资源(内存和CPU时间等)进行分配的基本单位,每一个进程都有自己的独立的一块内存空间、一组系统资源,其内部数据的状态都是完全独立的。不同点:同类的多个线程共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈。

2.什么是前台线程,什么是后台线程?
解: 对于前台线程,应用程序必须运行完所有的前台线程才可以退出,用Thread方法创建的线程默认为前台线程;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。

3.创建线程有几种方法?它们之间的区别是什么?
解:创建线程的方法主要有2种。
(1)继承Thread类,重写run()方法:

public class test extends Thread {
public static void main(String[] args) {
	Thread a=new test();
	a.start();
	System.out.println("This is main thread.");
}
public void run() {
	System.out.println("This is another thread.");
}
}

(2)实现runnable接口,创建线程时传入实现接口类的对象。

public class test implements Runnable {
public static void main(String[] args) {
	test my=new test();
	Thread a=new Thread(my);
	a.start();
	System.out.println("This is main thread.");
}
public void run() {
	System.out.println("This is another thread.");
}
}

继承Thread类重写run()方法覆盖掉父类的run()方法。实现runnable接口,创建线程时传入实现类对象,执行Thread类的run()方法,Thread类的run()方法体中调用传入的实现类对象的run()方法。

4.线程的生命周期有哪些状态?哪些方法可以改变这些状态?
解:(1)创建状态。(2)可运行(就绪)状态。(3)运行中状态。(4)阻塞状态。(5)死亡状态。
改变线程状态的方法:
(1)线程睡眠
public static void sleep(long millis)throw InterruptedException
当前线程睡眠(停止执行)若干毫秒,线程由运行中的状态进入阻塞状态,睡眠时间过后线程进入可运行状态。
(2)暂停线程
public static void yield()
yield()暂停当前线程执行,允许其他线程执行。该线程仍处于可运行状态,不转为阻塞状态。此时,系统选择其他同优先级线程执行,若无其他同优先级线程,则选中该线程继续执行。
(3)链接线程
join方法使当前线程暂停执行,它有一下3种用法:
①等待线程结束
public final void join()throws InterruptedException
②最多为线程等待millis毫秒
public final void join(long millis)throws InterruptedException
③最多为线程等待millis毫秒+nanos纳秒
public final void join(long millis,int nanos)throws InterruptedException
如果当前线程被强行中断,join方法会抛出InterruptedException 异常。

5.什么是线程安全?为什么会产生线程安全问题?如何解决线程安全问题?
解:当多个线程同时调用一个对象的同一方法,会导致程序运行不如人们的预期,从而产生危害,这就是线程的安全问题。为了解决线程安全问题,Java引入监视器来保证共享数据操作的同步性。任何对象都可作为一个监视器,关键字synchronized修饰某个对象后,该对象就成为监视器。

6.什么是线程的同步通信?同步通信又是如何实现的?
解:
多个线程在操纵共享资源——实例变量时,为了保证每个线程能正常执行操作,保证共享资源能正常访问和修改。Java引入了同步进制。

具体做法是在有可能引起共享资源竞争的代码前加上synchronized标记。这样的代码被称为同步代码块。

每个Java对象都有且只有一个同步锁,在任何时刻,最多只允许一个线程拥有这把锁。当一个线程要执行同步代码块时,必须先获得该对象的锁。

7.什么是死锁?
解:如果多个线程都处于等待状态,彼此需要对方所占用的监视器所有权,就构成死锁。

8.如何让某个对象的A方法内的代码块和另一个方法B实现同步?
解:

class Account{
	volatile private int value;
	volatile private boolean isMoney=false;
	synchronized void put(int i) {
		if(isMoney) {
			try {wait();}
			catch(Exception e) {}
		}
		value+=i;
		System.out.println("存入"+i+"账上金额为:"+value);
		isMoney=true;
		notify();
	}
	synchronized int get(int i) {
		if(!isMoney) {
			try {wait();}
			catch(Exception e) {}
		}
		if(value>i) value-=i;
		else {
			i=value;
			value=0;
		}
		System.out.println("取走"+i+"账上金额为:"+value);
		isMoney=false;
		notify();
		return i;
	}
}

class Save implements Runnable{
	private Account a1;
	public Save(Account a1) {
		this.a1=a1;
	}
	public void run() {
		while(true) {
			a1.put(100);
		}
	}
}

class Fetch implements Runnable{
	private Account a1;
	public Fetch(Account a1) {
		this.a1=a1;
	}
	public void run() {
		while(true) {
			a1.get(100);
		}
	}
}
public class test {
public static void main(String[] args) {
	Account a1=new Account();
	new Thread(new Save(a1)).start();
	new Thread(new Fetch(a1)).start();
}

}

输出:
存入100账上金额为:100
取走100账上金额为:0
存入100账上金额为:100
取走100账上金额为:0
存入100账上金额为:100
取走100账上金额为:0
存入100账上金额为:100
取走100账上金额为:0
存入100账上金额为:100
取走100账上金额为:0

9.设计一个程序产生两个线程A与B,B线程执行10秒钟后,被A线程中止。
解:

class Threada extends Thread{
	Threadb b=new Threadb();
	public void run() {
		System.out.println("A线程开始执行");
		Thread B=new Thread(b);
		B.start();
		try {System.out.println("A线程开始等待10s");sleep(10000);}
		catch(Exception e) {}
		B.stop();
		System.out.println("等待结束,B线程被中止");
	}
}

class Threadb implements Runnable{
	public void run() {
		System.out.println("B线程开始执行");
	}
}

public class test {
public static void main(String[] args) {
	Thread A=new Threada();
	A.start();
}
}

输出:
A线程开始执行
A线程开始等待10s
B线程开始执行
等待结束,B线程被中止

编写一个基于多线程的生产者/消费者程序,各产生10个生产者和消费者线程,共享一个缓冲区队列(长度自设),生产者线程将产品放入到缓冲区,消费者线程从缓冲区取出产品。
解:

class Account                              
{
    volatile private int value;
    synchronized void put(int i)                       
	{
    	try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
		}
		value = value + i; 
		System.out.println(Thread.currentThread().getName()+" 生产者--存入了 "+i+" 余量为:"+value);
	}
    synchronized int get(int i)                         
    {  
    	try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
		}
		if (value>i)
				value = value - i;             
			else                               
			{   i = value;
				value = 0;                     
			}
		System.out.println(Thread.currentThread().getName()+ " 消费者--消费了 "+i+" 余量为:"+value);
      return i;                      
    }    
}
class  Save implements Runnable            
{
    private Account a1;     
    public Save(Account a1)
    {
        this.a1 = a1;
    }
    public void run()
    {
        while(true){
			a1.put(1);			
	    }
    }
}
class Fetch implements Runnable            
{
    private Account a1;
    public Fetch(Account a1)
    {this.a1 = a1 ;}
    public void run()
    {       
		while(true){		
			a1.get(1);			
		}		
    }
}
public class test{
	public static void main(String[] args){
       Account a1 = new Account();
       new Thread(new Save(a1)).start(); 
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start(); 
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start();
       new Thread(new Save(a1)).start();
       //10个生产者和消费者
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
       new Thread(new Fetch(a1)).start();
	}
}

第十五章

5.利用URLConnetction对象编写程序返回某网站的首页,并将首页内容存放到文件当中。
解:

package test;
import java.io.*;
import java.net.*;

public class test{
	public static void main(String[] args) throws Exception{
       URL tirc=new URL("http://www.baidu.com/");
       BufferedReader in =new BufferedReader(new InputStreamReader(tirc.openStream()));
       String inputline;
       FileOutputStream fileoutputstream=null;
       File file=new File("test.txt");
       if(!file.exists()) file.createNewFile();
       fileoutputstream=new FileOutputStream(file);
       while((inputline=in.readLine())!=null) {
    	   fileoutputstream.write(inputline.getBytes("gbk"));
    	   fileoutputstream.flush();
       }
       in.close();
       fileoutputstream.close();
	}
}

结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值