第一课:Java进阶与Socket通讯实验

课程网站:

  • http://ss.sysu.edu.cn/~pml/dct/1_intro.html

相关文章:

  • 第一课:Java进阶与Socket通讯实验
  • 第二课:Socket通讯与HTTP服务器
  • 第三课:Java Web 编程原理
  • 第四课:RESTful Webservice 编程

解释 RuntimeException。例举它的1-2个子类,并用一个小程序验证捕获并处理异常的过程。

RuntimeException是Java中的一种异常类。与其他异常类不同,RuntimeException是非检查型异常,而其他的都是检查型异常。常见的RuntimeException的子类大约有以下几种:

NullPointerException - 空指针引用异常  
ClassCastException - 类型强制转换异常。  
IllegalArgumentException - 传递非法参数异常。  
ArithmeticException - 算术运算异常  
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常  
IndexOutOfBoundsException - 下标越界异常  
NegativeArraySizeException - 创建一个大小为负数的数组错误异常  
NumberFormatException - 数字格式异常  
SecurityException - 安全异常  
UnsupportedOperationException - 不支持的操作异常  

例子:NumberFormatException异常

public class Test {
    public static void main(String args[]) {
        int temp = Integer.parseInt("");
    }
}

当执行这个程序的时候,将抛出NumberFormatException异常,如图:


第一课:Java进阶与Socket通讯实验_第1张图片
NumberFormatException异常

参考资料:
http://lelglin.iteye.com/blog/1454999
http://blog.csdn.net/feihong247/article/details/7873540


在生产实践中,每个业务模块都会定义一个异常基类,例如 Account 模块定义 AccountException 继承 Exception,然后在定义各种业务异常 如 OutOfMoneyException 继承 AccountException。请使用 UML 绘图工具 UMLet 绘制这些类及其关系。

UMLet介绍:

UMLet是一款特别棒的专业UML绘图工具。可以更好地绘制UML,从而更容易分析软件的架构。
下载地址:http://umlet.com/

UML图:

第一课:Java进阶与Socket通讯实验_第2张图片
UML图

类的方法中,如果抛出一个异常类型,方法声明中能否不申明?例如 public void transfer(double amount) throws OutOfMoney 去掉 throws OutOfMoney。去掉的后果是什么?

不行。方法后面的throws主要是声明这个方法会抛出这种类型的异常,使其他地方调用它时知道要捕获这个异常,使得提醒必须做出处理。如果不申明throws编译是不会通过的。

参考资料:
http://www.cnblogs.com/zhangzongle/p/5425843.html

Socket是两个进程联系的虚拟通道。如果服务器程序不启动,仅运行客户端,客户端会阻塞还是出错?在那条语句?

会出错,抛出一个ConnectException异常。出错语句为:

Socket server = new Socket(args[0], Integer.parseInt(args[1]));

即在建立客户端的时候出错。

如果程序运行到一半,服务端意外退出,客户端会表现出什么行为?

如果不进行数据传输,则不会有问题;如果向服务端发出数据,客户端将抛出一个SocketException异常,然后中止了程序。

(!)BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); 语句是典型的设计模式“装饰模式”,请检索自学“Decorator Pattern”,请使用 UML 绘图工具 UMLet 绘制涉及的类及其关系。

……

案例中 ServerSocket 能否支持两个或以上客户端?为什么?

不能支持两个。因为在代码中,只实现了接受一个服务端。

Socket client = server.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());

如果要支持多个,就需要开多线程。

线程与进程的区别?

进程是运行中的程序。线程是进程的一个实体,是CPU调度的基本单位。两者有几个主要区别:

  1. 一个程序至少有一个进程,一个进程至少有一个线程.
  2. 线程的划分尺度小于进程,使得多线程程序的并发性高。
  3. 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
  4. 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  5. 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

参考资料:
http://blog.csdn.net/yaosiming2011/article/details/44280797

Java 两个启动线程方法各有哪些优点、缺点?

Java实际上有三种启动线程的方式:


  1. 继承Thread
public class java_thread extends Thread {  
    public static void main(String args[])  
    {  
        (new java_thread()).run();  
        System.out.println("main thread run ");  
    }  
    public synchronized void run()  
    {  
        System.out.println("sub thread run ");  
    }  
}
  1. 实现Runnable接口
public class java_thread implements Runnable {  
    public static void main(String args[])  
    {  
        (new Thread(new java_thread())).start();  
        System.out.println("main thread run ");  
    }  
    public void run()
    {
        System.out.println("sub thread run ");  
    }
}
  1. 直接在函数体使用
void java_thread()  
{  
  
     Thread t = new Thread(new Runnable(){  
            public void run(){  
            mSoundPoolMap.put(index, mSoundPool.load(filePath, index));  
            getThis().LoadMediaComplete();  
            }});  
        t.start();  
}

三种方式的优缺点比较


实现Runnable接口优势:

  • 适合多个相同的程序代码的线程去处理同一个资源
  • 可以避免java中的单继承的限制
  • 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

继承Thread类优势:

  • 可以将线程类抽象出来,当需要使用抽象工厂模式设计时。
  • 多线程同步

在函数体使用优势:

  • 无需继承thread或者实现Runnable,缩小作用域。

参考资料:
http://blog.csdn.net/typename/article/details/7212512

(!)简述 Java 中 synchronized 的用法。

synchronized是Java中的关键字,是一种同步锁。用同步锁可以保证,在多线程的情况下,防止操作互相冲突。

synchronized大概有四种用法:

  1. 修饰某段代码块:
synchronized(this) {
      // Todo
}
  1. 修饰某个对象:
synchronized(obj) {
      // Todo
}
  1. 修饰某个方法:
public synchronized void run() {
     // Todo
}
  1. 修改一个类:
synchronized(ClassName.class) {
      // todo
}

参考资料:
http://blog.csdn.net/luoweifu/article/details/46613015

对象序列化二进制流中能否存在指针值(内存地址引用)?为什么?

不能。因为序列化的目的是为了储存对象,以便未来通过反序列化把对象再提取出来。如果存在内存地址,那么下次提取的时候,对应的地址就有可能不是原来的地址,从而导致程序崩溃。

(!)为了使序列化和反序列化变得易于理解,人们提出了使用 Json,XML,Yaml等格式的文本表示对象。请写一个小程序,选择其中一种格式,在控制台输出Account对象

转化为XML可以用XStream。但是用XStream首先需要两个jar包:

  • xpp3_min-1.1.4c.jar
  • xstream-1.3.jar

代码如下:

import com.thoughtworks.xstream.XStream;

public class Test {
    public static void main(String[]args) {
        Account obj = new Account();
        XStream xStream = new XStream();
        xStream.alias("obj", obj.class);
        String xml = xStream.toXML(obj);
        System.out.println(xml);
    }
}

参考资料:
http://blog.csdn.net/baple/article/details/18219099

instanceof 很好用,为什么需要反射技术呢?请结合案例简述反射的必要性。

反射技术:


主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

例如,我们可以通过三种方式获取类:

//第一种方式:  
Classc1 = Class.forName("Employee");  
//第二种方式:  
//java中每个类型都有class 属性.  
Classc2 = Employee.class;  
   
//第三种方式:  
//java语言中任何一个java对象都有getClass 方法  
Employeee = new Employee();  
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)  

然后获取类之后,我们就可以直接创建对象或者获取类的属性。这样在编程的时候就可以更加灵活,更加简单。
例如如果我们要找一个对象是不是某个类的特例,如果用instanceof就比一般的机制简单。

参考资料:
http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html
http://blog.csdn.net/liujiahan629629/article/details/18013523

代理模式(proxy pattern)的特征是代理类与委托类有同样的接口。请使用 UML 绘图工具 UMLet 绘制案例代理模式的 UML 图(图8),并用自然语言简单描述静态代理类 StaticServiceProxy 的工作过程。

第一课:Java进阶与Socket通讯实验_第3张图片
UML图

StaticServiceProxy 除了构造方法,只有getAccount方法。代码如下:

public String getAccount(String Name) {
  Connector connector = null;
  try {
     connector = new Connector(host, port);
     RemoteCall call = new RemoteCall("AccountService", "getAccount", new Class[] { String.class }, new Object[] { Name });
     connector.send(call);
     call = (RemoteCall)connector.receive();
     Object result = call.getResult();
     return (String)result;
  } catch (Exception e) {
     e.printStackTrace();
  } finally  {
     if (connector != null) connector.close();
  }
   return Name;
}

简述静态代理和动态代理的区别。

静态代理:


由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

静态代理类优缺点


优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:

  • 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
  • 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

动态代理


动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

动态代理类优缺点


优点:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。在本示例中看不出来,因为invoke方法体内嵌入了具体的外围业务(记录任务处理前后时间并计算时间差),实际中可以类似Spring AOP那样配置外围业务。

缺点:
诚然,Proxy 已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。

有很多条理由,人们可以否定对 class 代理的必要性,但是同样有一些理由,相信支持 class 动态代理会更美好。接口和类的划分,本就不是很明显,只是到了 Java 中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。

参考资料:
http://layznet.iteye.com/blog/1182924

你可能感兴趣的:(第一课:Java进阶与Socket通讯实验)