Java语言程序设计期末复习---简答题

第一章

1.Java语言有哪些特点?

(1)简单:简单而高效,Java系统(编译器和解释器)所占空间不到250KB。

(2)面向对象:是纯面向对象的语言。

(3)平台无关性与可移植性:可以在不同操作系统上运行。它既是编译型也是解释型语言。

(4)稳定性和安全性:摒弃了C++中的不安全因素——指针数据类型。保证字节码文件加载的安全和访问系统资源的安全。

(5)多线程并且是动态的:多线程使应用程序可以同时进行不同的操作和处理不同的时间。在执行过程中可以动态加载各类库,这一特点使之非常适合于网络运行,同时也非常有利于软件的开发,即使更新类库也不必重新编译使用这一类库的应用程序。

(6)高性能:通常解释型语言的执行效率要低于直接执行机器码的速度,但Java的字节码转换成机器码非常简单和高效。

(7)分布式:物理上分布,逻辑上统一。其内容包括数据分布和操作分布两个方面。数据分布是指数据可以分散存放于网络上的不同主机中,以解决海量数据的存储问题;操作分布则是指把计算分布到不同主机上进行处理,这就如同许多人协同共同完成一项大而复杂的工作一样。

第四章

1.名词解释:构造方法、抽象。

(1)构造方法是一种特殊的方法,它是一个与类同名且返回值类型为同名类类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的初始化。当类实例化一个对象时会自动调用构造方法。构造方法和其他方法一样也可以重载。

(2)从具体事物抽出、概括出它们共同的方面、本质属性与关系等,而将个别的、非本质的方面、属性与关系舍弃,这种思维过程,称为抽象。

2.对象位于内存何处?声明能引用对象的实质是什么?

例如:Person per = new Person();
per这个引用在栈内存中,而new出来的对象是在堆内存中,栈中的per指向了堆中的新分配的空间。
如果只有Person per;这时的per叫做 声明。

3.对象和基本数据类型作为参数传递时,有什么不同?

基本数据类型作为参数在方法中的传递是值传递,对象是引用传递,传递的是对象的地址。

5.对象在什么条件下成为垃圾?什么情况下释放垃圾对象,如何证明一个对象被释放了?

(1)对象在没有任何引用时成为垃圾。

(2)系统在内存不足时会释放垃圾,或者手动 System.gc() 释放垃圾。

6.final修饰符都有什么作用?

(1)Java中final修饰符既可以修饰类、方法,也可以修饰变量

(2)用final修饰的类不能被继承

(3)用final修饰的方法不可重写

(4)用final修饰的变量必须初始化,且之后不能赋值

7.static修饰的属性和方法有什么特点?

static修饰属性或方法后,属性和方法不在属于某个特定的对象,而是所有共享,也可以说是static成员不依赖某个对象,在类加载时就被初始化。static修饰的属性或方法,可以直接使用类名调用,而不用先实例化对象再调用。

10.请在 dislpay 函数中用递归方式输出如下图型。

public class List {
	
    public static void display(int n){
        if(n <= 0){ return;}
        for(int i = 1 ;i <= n; i++){
            System.out.print(n + " ");
        }
        System.out.println();
        display(n-1);
    }
    public static void main(String[] args) {
        display(9);//这里改变 n 的值
    }
}

第五章

2.封装是如何实现的?

封装通过访问控制符实现的,只有通过授权才能访问数据。

3.对象之间如何相互作用?作用的条件是什么?

通过消息,拥有访问类数据成员或成员方法的权限。

4.protected修饰符的特点?

只有包内其它类、自己和子类可以访问。

6.重载的方法之间一般有什么关系?

方法名相同,而参数不同。返回类型可以相同也可以不同。

7.子类覆盖父类方法需要什么条件?子类中定义与父类同名的方法一定是覆盖吗?

方法名,参数,返回类型全部相同,内容不同。不一定

8.封装、继承和多态在面向对象设计中的用途是什么?

(1)封装可以保护类的数据成员,隐藏信息。

(2)子类继承父类的属性和方法后,不用重新编写代码,提高了代码复用性。

(3)多态最重要的是子类的功能可以被父类的引用调用,向后兼容。

第六章

2.子类对象实例化的具体过程是什么?

(1)子类在构造对象时候,必须访问父类的构造函数,为了完成这个必须的动作,就在子类的构造函数中加入了super()语句。

(2)如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数,否则子类无法完成初始化。

(3)在构造函数生效之前,程序会先执行静态的成员活方法的初始化。

3.类的域变量和方法中定义的局部变量在初始化上有何区别?

类的域变量在类初始化的时候就开始创建了,而方法中的变量是在调用到该方法时,才会为该变量创建。

5.接口有什么作用?

接口最直接的好处就是提供了一个统一的操作方法名,然后同样的方法名在不同的类中可以有不同的具体实现过程,这样的结果就是在操作实现了该接口的类的对象时,不用去事先了解该方法的名字,而采用统一的名字进行调用。

6.抽象类与接口的异同点是什么?

相同点:

(1)不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

(2)都有自己的声明,可以引用子类或实现类对象

不同点 :

(1)抽象类可以有域变量,接口没有,只能是静态常量。

(2)抽象类可以有具体方法;接口全是抽象方法。

(3)抽象类实现靠子类继承,接口靠实现类。

7.引用比较方法有哪些?

(1)equals方法比较。

(2)使用“==”进行比较。

(3)使用instanceof比较引用类型

8.内部类的作用是什么?什么情况下使用匿名内部类?

作用:

(1)内部类可以很好的实现隐藏。一般的非内部类,是不允许有 private 与protected权限的,但内部类可以。

(2)内部类拥有外围类的所有元素的访问权限。

(3)可是实现多重继承。

(4)可以避免修改接口而实现同一个类中两种同名方法的调用。

匿名内部类:

匿名内部类是内部类的一种特殊情况。它只有一个实例,而且没有引用。所以,一般在能用内部类实现,但是实例只用一次的情况下使用它(可以减少资源开销)。

10.什么是数据隐藏?如何证明子类对父类同名方法进行重新定义,只能是方法的覆盖,而不是方法的隐藏?

(1)在子类对父类的继承中,如果子类的成员变量和父类的成员变量同名,此时称为子类隐藏(override)了父类的成员变量。

(2)覆盖:子类重写父类的方法,要求方法名和参数类型完全一样(参数不能是子类),返回值和异常比父类小或者相同(即为父类的子类),访问修饰符比父类大或者相同。

隐藏:父类和子类拥有相同名字的属性或者方法( 方法隐藏只有一种形式,就是父类和子类存在相同的静态方法)时,父类的同名的属性或者方法形式上不见了,实际是还是存在的。

第七章

1.“程序中凡是可能出现异常的地方必须进行捕获或拋出”,这句话对吗?

不对。
异常分两类,runtime异常和非runtime异常。
runtime异常,比如NullPointException等,这一类你不在程序里面进行try/catch,编译不会出错。
非runtime异常,比如SqlException等或自定义的exception,这一类在程序里不进行try/catch或throws,编译就会出错。

第八章

3.String类型有什么特点?

(1)一旦赋值,便不能更改其指向的字符对象

(2)如果更改,则会指向一个新的字符对象

(3)不能为null

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

stringA.equals(stringB);进行值比较
stringA==stringB;进行引用比较

5.String与StringBuffer的区别是什么?如何相互转化?

StringBuffer是一个具有对象引用传递特点的字符串对象。

//数据类型由String转为StringBuffer
String s = “hello”;
StringBuffer sb = new StringBuffer(s); //调用的构造函数
//String也有相反的构造函数
String a = new String(sb);
//还可以用StringBuffer的一个方法
String str = sb.toString() ;

第九章

1.线程和进程的联系和区别是什么?

区别:

(1)进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统进行资源分配和调度的一个独立单位。

(2)线程是进程的一个实体,是CPU调度和分配的基本单位。线程基本不拥有系统资源,与同一个进程的其他线程共享进程中所拥有的所有资源。

联系:

一个进程可以包括多个线程。

2.什么是前台线程,什么是后台线程?

应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。

3.创建线程有几种方法?它们之间的区别是什么?

第一种方式:使用Runnable接口创建线程

(1)可以实现多个线程资源共享

(2)线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法

第二种方式:直接继承Thread类创建对象

(1)Thread子类无法再从其它类继承(java语言单继承)。

(2)编写简单,run()方法的当前对象就是线程对象,可直接操作。

4.线程的生命周期有哪些状态?哪些方法可以改变这些状态?

(1)创建状态:线程对象已经创建,还没有在其上调用start()方法。

(2)可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。

(3)运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。

(4)阻塞状态:这是线程有资格运行时它所处的状态。如执行了join/sleep/wait方法,会让出CPU,只有当引起阻塞的原因消除时,线程才能转入就绪状态。

(5)死亡态:当线程的run()方法完成时就认为它死去。或者抛出一个未捕获到的Exception或Error。

5.什么是线程安全?为什么会产生线程安全问题?如何解决线程安全问题?

(1)线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

(2)原因是由于不同线程获取到资源时进行运算,但未来得及写入时,线程改变,则另外线程读入的资源就是错误,导致所有线程写入读入不同步。

(3)解决办法:
使用监视器,使用关键字synchronized监视同步代码块,当一个线程获得监视权限时,别的线程就无法获得,保证每时每刻只有一个线程调用某一方法

6.什么是线程的同步通信?同步通信又是如何实现的?

(1)线程同步通信是希望实现两个或多个线程之间的某种制约关系

(2)实现:首先是用监视器synchronized来保证每次只有一个线程调用方法,其次引入一个boolean型标志来判断该线程是否执行或wait,两个线程时使用notify(),多个线程时用notifyAll()来让出监视器并唤醒其他线程。这样就实现了线程之间的关系。

7.什么是死锁?

线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。

第十章

8.如何实现集合对象排序?定义一个复数类并按照复数的实部大小对复数对象进行排序。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Plural{

    private double x;
    private double y;   
    public double getX() {return x;}
    public void setX(double x) {this.x = x;}
    public double getY() {return y;}
    public void setY(double y) {this.y = y;}
    public Plural() {x = 0; y = 0;}
    public Plural(double x, double y) {this.x = x; this.y = y;}
    public void show() {
        if (y == 0)
            System.out.println(x);
        else if(y<0)
            System.out.println(x + " - " + -y + "i");
	        else 
	        	System.out.println(x + " + " + y + "i");
    }
}

class PluralComparator implements Comparator<Plural> {
	//Comparator接口因为有2个参数,所以要单独写一个类
	//而Comparable接口是一个参数,可以写到上面那个类,直接实现接口,这里没有用
    @Override
    public int compare(Plural o1, Plural o2) {
        return o1.getX() < o2.getX() ? 1 : -1;
    }
}
public class test {

    public static void main(String[] args) {
    	ArrayList<Plural> lst = new ArrayList<>();
        lst.add(new Plural(0, 2.3));
        lst.add(new Plural(-5, 4));
        lst.add(new Plural(-1.2, -3));
        lst.add(new Plural(1, 0));
        Collections.sort(lst, Collections.reverseOrder(new PluralComparator()));
        						//获取要不要交换
        for(Plural p : lst)
            p.show();
    }
}

10.对第7章第6题进行适当改造,将异常类型与中文提示存储在一种集合类当中,从而实现相应的功能。

import java.util.HashMap;

class myException{
    @SuppressWarnings("rawtypes")//用哈希图来存储
    public HashMap<Class, String> hm = new HashMap<>();
    public myException() {
        hm.put(NullPointerException.class, "空指针异常");
        hm.put(ArithmeticException.class, "算术异常");
        hm.put(Exception.class, "其他异常");
    }
}
public class test {

    public static void main(String[] args) {
        myException ex=  new myException();
        try {
        	String s = null;
            //System.out.println(1/0);//除零异常
            System.out.println(s.charAt(0));//空指针异常
        }catch (NullPointerException e) {
        	Class<?> c = NullPointerException.class;
            System.out.println(ex.hm.get(c));
        }catch (ArithmeticException e) {
        	Class<?> c = ArithmeticException.class;
            System.out.println(ex.hm.get(c));
        }catch (Exception e) {
        	Class<?> c = Exception.class;
            System.out.println(ex.hm.get(c));
            e.printStackTrace();
            //在命令行打印异常信息在程序中出错的位置及原因
        }
    }
}

第十四章

3.完成下面方法中的代码,要求建立一个缓冲区,将字节输入流中的内容转为字符串。
static String loadStream(InputStream in) throws IOException {…}

import java.io.*;
public class test {
	 static String loadStream(InputStream in) throws IOException {
	        //int ptr;
	        //in = new BufferedInputStream(in);
	        StringBuffer buffer = new StringBuffer();  
	        int n = 1,i=5;
	        byte[] buf = new byte[n];//缓冲区,大小为1字节
	        while(i-->0) {
	         //因为read主要用于读文件,而我这里用它来一个字节的从键盘读,所以不会返回-1,于是我用i来设置读取长度为5
	        	in.read(buf,0,n);
	        	System.out.println(new String(buf));//按字节显示一下
	            buffer.append(new String(buf));    //连接一个字符串
	        }
	        return new String(buffer);  
	  }
	
	public static void main(String[] args) throws IOException {
		InputStream in = new BufferedInputStream(System.in);//in必须要初始化一个对象,不能为null
		String test=loadStream(in);
		System.out.println("result=: "+test);
	}
}

4.编写程序,将一个字符串转为字节数组输入流,将这个流中所有小写字母换成大写字母并写入字节数组输出流中,再将数组输出流转为字符串。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class test {
public static void main(String[] args) {
	String str = "Hello World!"; //源字符串
	//字节数组输入流
	ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
	//字节数组输出流
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	//循 环读取
	int b = -1;
	while((b = bais.read()) != -1){
		//把小写字母转换成大写字母
		System.out.print(" "+(char)b);
		if(b >= 97 && b <= 122){ //大写字母从 65~90, 小写字母从 97~122
			b -= 32;
		}
		//写回到字节数组输出流中
		baos.write(b);
	}
	System.out.println();
	//输出,并把字节数组输出流转换成字符串
	String out = baos.toString();
	System.out.println(out);
	}
}

5.完成下面方法中的代码,方法中的参数为一个文本文件的名称,要求将文件中的内容转为字符串。
static public String loadFile(String filename){…}

import java.io.*;
public class test {
	static public String loadFile(String filename) {
	    File file = new File( filename );//建立文件对象
	    try {
	        Reader rdr = new FileReader( file );//建立读文件对象
	        long sz = file.length();
	        //一次全部读入
	        char[] ch = new char[(int)sz]; //开辟一次读入的大小  
	        rdr.read(ch);
	        rdr.close();
	        return new String(ch);//变为字符串
	    } catch(IOException ioe) {
	        return null;
	    }
	}
	public static void main(String[] args) {
		//先在test工程的目录下手动新建一个test.txt(和bin,src文件夹并列的位置),自己保存点内容
		//设定文件名
		String fname = "test.txt";
		String test=loadFile(fname);//调用方法
		System.out.println(test);
	}
}

6.完成下面方法中的代码,将字符串contents中的内容写入文件filename中。
static public boolean saveFile(String filename,String contents){…}

import java.io.*;
public class test {
	static public boolean saveFile(String filename, String contents) {
	    try {
	        File file = new File( filename );
	        if(!file.exists()) {//判断该txt是否存在
	              file.createNewFile();//不存在就在当前目录下新建一个
	        }
	        Writer wtr = new FileWriter( file );
	        char[] ch = contents.toCharArray();//把字符串转为字符数组
	        wtr.write(ch);
	        wtr.close();
	        return true;
	    } catch(IOException ioe) {
	        return false;
	    }
	} 

	public static void main(String[] args) throws IOException {
		String fname = "test.txt";//给定文件名
		String contents = "hello world!";//给定写入的字符串
		if(saveFile(fname,contents))System.out.println("contents is save!");//显示是否成功
	}
}

7.socket套接字有一个方法getInputStream(),其含义是得到从网络上传过来的数据流。现要求编写一段程序,将接收的数据存入文件。

客户端:
import java.io.*;
import java.net.Socket;

public class TalkClient {
    public static void main(String[] args)throws IOException {
        Socket socket = new Socket("127.0.0.1",5000);
        OutputStream out = socket.getOutputStream();
        int i =10;
        while(i-->0)  
        {
        	out.write("HELLO".getBytes());
        	out.flush();
        }
        System.out.println("发送消息完毕!");
        out.close();
        socket.close();
    }
   }
   
服务器端:
import java.io.*;
import java.net.*;
public class MultiTalkServer{
	public static void main(String[] args)throws IOException {
        ServerSocket server = new ServerSocket(5000);//打开服务器制定端口,等待客户端连接
        //获得与服务器相连的套接字对象     套接字:绑定ip地址和端口号的网络对象
        Socket socket = server.accept();
        //查看该地址文件夹是否存在,如果不存在,创建一个
        String name = "test.txt";        //文件名,按照我的设定,应该在test文件夹下面
        File file = new File(name); 
        if(!file.exists()){
            file.createNewFile();
            System.out.println("文件已新建!");
        }   
        InputStream in = socket.getInputStream();  //套接字的字节输入流,读取客户端传过来的数据
        FileOutputStream fos = new FileOutputStream(name);  //创建输出流对象           
        byte[] data = new byte[5];//一次读取5字节,方便阅读,因为客户端传的就是5个字节
        int len = 0;
        //如果客户端没有关闭socket输出流,这里的read方法会一直读取
        while((len = in.read(data)) != -1) 
        {
        	fos.write(data, 0, len);
        	fos.write("\r\n".getBytes());// 写入一个换行
        }  
        System.out.println("上传成功!");
        server.close();
        fos.close();
    }
}

8.编写程序实现文件查找功能。提供两个参数,第一个参数为查找的起始路径,第二个参数为要查找的文件名称。如果找到,则给出文件的完整路径,否则提示文件不存在。

import java.io.File;
public class test
{
	String path = null;
	public String searchFile(File dir, String fileName) 
	{
		if(dir.isFile())//测试当前dir是否为文件
		{
			if(dir.getName().equals(fileName))//此时表明dir为一个文件,和我们要找的文件比对一些
				path = dir.getAbsolutePath();
		}
		if (dir.isDirectory())//进入if表明dir为一个文件夹
		{
			//列出dir中所有的文件和目录
			File[] files = dir.listFiles();
			File f ;
			for (int i=0;i<files.length;i++ ){
				f = files[i];
				path = searchFile(f, fileName);//递归调用,因为文件夹可能有多层
			}				
		}
		return path;
	}
 
	public static void main(String[] args) {
		File dir = new File("D:/360Downloads/");//此处不能写D:/,原因应该是根目录不支持吧
		String fileName = "filelist.dat";	//自己修改个文件名	
		if (!dir.exists())
		{
			System.out.println("目录不存在:" + dir);
			System.exit(0);
		}
		String path = new test().searchFile(dir,fileName);
		if(path!=null)
			System.out.println("文件完整路径:" + path);
		else
			System.out.println("不存在此文件");
	}
}

第十五章

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

import java.io.*;
import java.net.*;

public class html {

    public static void main(String[] args) throws IOException {
        URL url=  new URL("https://www.baidu.com/");
        URLConnection con = url.openConnection();
        BufferedReader is=  new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
        //三层括号由右往左,以指定字符集获得url的字节输入流,转换为字符输入流,按行读取,更高效
        FileOutputStream fos = new FileOutputStream("E:\\test.txt");//指定路径,它会自动新建一个文件
        String line;
        while((line = is.readLine()) != null ) {
            line = line + "\n";
            fos.write(line.getBytes("UTF-8"));//同样要指定字符集
            fos.flush();
        }
        System.out.println("Successful!");
        is.close();
        fos.close();
    }
}

仿照例15.4,编写完整的基于Socket的多客户/服务器通信程序

客户端:
import java.io.*;
import java.net.Socket;

public class TalkClient {

    public static void main(String[] args) {
        Socket socket = null;
        try {
            socket = new Socket("127.0.0.1", 4700);//本机地址
        } catch (IOException e) {
            System.out.println("Can't not listen to " + e);
        }
        //System.out.println("111111");
        try {
            BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));//构建各种输入输出流对象
            BufferedWriter os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            String readLine;
            while(!(readLine = sin.readLine()).equals("bye")) {
                os.write(readLine + "\n");
                os.flush();
                System.out.println("Server " + ": " + is.readLine());
            }
            os.close();
            is.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器 + 线程:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

class ServerThread extends Thread{
    Socket socket = null;
    int clienNum;
    public ServerThread(Socket socket, int num){
        this.socket = socket;
        clienNum = num + 1;
    }
    public void run(){
        try {
            String readLine;
            BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));//构建各种输入输出流对象
            BufferedWriter os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            System.out.println("connected with: " + socket);
            System.out.println("Client " + clienNum + ": " +  is.readLine());
            readLine = sin.readLine();
            while(!readLine.equals("bye")){
                os.write(readLine + "\n"); 
                os.flush();
                System.out.println("Client " + clienNum + ": " +  is.readLine());//添加是哪个客户端发过来的消息
                readLine = sin.readLine();
            }
            os.close();
            is.close();
            socket.close();
        } catch (IOException e) {
            System.out.println("Error: " + e);
        }
    }
}
public class MultiTalkServer {
    private static int clientNum = 0;

    public static void main(String[] args) throws IOException {
        ServerSocket server = null;
        boolean listening = true;
        try {
            server = new ServerSocket(4700);//设置监听端口
        } catch (IOException e) {
            System.out.println("Could not listen on port: 4700");
            System.exit(-1);
        }
        while(listening){
            new ServerThread(server.accept(), clientNum).start();//启动新线程
            clientNum++;
        }
        server.close();
    }
}

仿照例15.5,编写完整的基于数据报的多客户/服务器通信程序

客户端(只能启动一个,这是数据报的规定,但启动多个不会报错):
import java.io.*;
import java.net.*;
public class QuoteClient {
	public static void main(String[] args) throws IOException{
		 DatagramSocket socket=new DatagramSocket();//创建数据报套接字
		 BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
		 String readLine;
		 InetAddress address=InetAddress.getByName("127.0.0.1");//Server的IP信息
		 while(!(readLine = sin.readLine()).equals("bye")) {
		 byte[] buf = readLine.getBytes();
		 //创建DatagramPacket对象
		 DatagramPacket packet=new DatagramPacket(buf, buf.length, address, 4445);
		 socket.send(packet); //发送
		 buf = new byte[256];
		 //创建新的DatagramPacket对象,用来接收数据报
		 packet=new DatagramPacket(buf,buf.length);
		 socket.receive(packet); //接收
		 buf = packet.getData();
		 //根据接收到的字节数组生成相应的字符串
		 String received=new String(buf);
		 //打印生成的字符串
		 System.out.println("Quote of the Sever: "+received );		 
		}
		 socket.close(); //关闭套接口
	}
}

服务器 + 线程:
import java.io.*;
import java.net.*;

class QuoteServerThread extends Thread//服务器线程
{  
	protected DatagramSocket socket=null;//记录和本对象相关联的DatagramSocket对象
	protected BufferedReader in=null;//用来读文件的一个Reader
	protected boolean moreQuotes=true;//标志变量,是否继续操作
	public QuoteServerThread() throws IOException {//无参数的构造函数
    this("QuoteServerThread");//以QuoteServerThread为默认值调用带参数的构造函数

	}
	public QuoteServerThread(String name) throws IOException {
		super(name); //调用父类的构造函数
		socket=new DatagramSocket(4445);//在端口4445创建数据报套接字		
		in= new BufferedReader(new InputStreamReader(System.in));
	}	
	 public void run() //线程主体
	 {
		while(moreQuotes) {
			try{
				byte[] buf=new byte[256]; //创建缓冲区
				DatagramPacket packet=new DatagramPacket(buf,buf.length);
				//由缓冲区构造DatagramPacket对象
				socket.receive(packet); //接收数据报				
				//打印出客户端发送的内容
				System.out.println("Client : "+new String(packet.getData())); 
				//从屏幕获取输入内容,作为发送给客户端的内容
				String dString= in.readLine();    
				//如果是bye,则向客户端发完消息后退出
				if(dString.equals("bye")){moreQuotes=false;}
				buf=dString.getBytes();//把String转换成字节数组,以便传送
				//从Client端传来的Packet中得到Client地址
				InetAddress address=packet.getAddress();
				int port=packet.getPort(); //端口号
				//根据客户端信息构建DatagramPacket
				packet=new DatagramPacket(buf,buf.length,address,port);
				socket.send(packet); //发送数据报
			}catch(IOException e) { //异常处理
			    e.printStackTrace(); //打印错误栈
				moreQuotes=false; //标志变量置false,以结束循环
			}
		 }
		 socket.close(); //关闭数据报套接字
	   }	
}

public class QuoteServer{
	public static void main(String args[]) throws java.io.IOException
	{
		new QuoteServerThread().start();//启动一个QuoteServerThread线程
	}
}

16.利用串行化技术和Socket通信,将一个客户端构造的对象传送到服务器端,并输出该对象的属性值。
注:共三个class,那个User也可以写到另外两个里面,不过分开会清楚一点,User类就是用来传送的对象模板。

User对象类:
import java.io.Serializable;

public class User implements Serializable{

	/**
	 * 下面那句serialVersionUID是用来防止旧版本修改出错的,这里我们用不上,但确实是一个漏洞,所以要设置默认UID
	 */
	private static final long serialVersionUID = 1L;
	String Name;
	String Password;
	User()//默认构造函数
	{
		Name="null";
		Password="00000";
	}
	User(String name,String password)//带参数的构造函数
	{
		Name=name;
		Password=password;
	}
	void setName(String name) {Name=name;}
	void setPassword(String password) {Password=password;}
	String getName() {return Name;}
	String getPassword() {return Password;}
}
客户端:
import java.io.*;
import java.net.Socket;

public class TalkClient {
	public static void main(String[] args) throws IOException{
	    Socket socket = null;
		try {
			socket = new Socket("127.0.0.1", 4700);
		} catch (IOException e) {
			e.printStackTrace();
		} 
        User u1 = new User();
        u1.setName("Tommy");
        u1.setPassword("1234567"); //赋值
        //把对象串行化为可输出的形式,输入到Socket的输出流里面
        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
        out.writeObject(u1);//以串行化方式写入这个对象
        System.out.println("successful!");
        out.flush();
        out.close();//超级重要,要是没有close来正常退出,服务器端就会被意外中止,导致出错。
    }
}
服务器端:
import java.io.*;
import java.net.*;
public class MultiTalkServer {
	public static void main(String[] args) throws ClassNotFoundException, IOException {
	    ServerSocket server;
	    Socket socket = null; 
        try {
            server = new ServerSocket(4700);
            socket = server.accept();
            //这步很重要,socket.getInputStream()是输入流,要用ObjectInputStream装配为串行化输入流
            ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
            System.out.println("连接成功!");
            User u2 = (User) in.readObject();//接受一个被串行化的对象,赋值给u2
            System.out.println("Name: "+ u2.getName() + "  Password: " + u2.getPassword());
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
	}
}
  • 13
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小天才才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值