渣渣小本求职复习之路每天一博客系列——Java基础(4)

  前情回顾:昨天回顾了继承与多态,还介绍了方法重写、方法重载、抽象方法、抽象类、关键字与范围等内容,最后还介绍一下GC的内容。

  这两天看书越来越有感觉了,喜欢上坐在书桌前翻书的feel。这让我想起了作业本在微博上发的一段话:“在你的一生中,有一个“开窍时刻”,就是你的职业或学业带给你那些百思不得其解的问题、矛盾、纠结,在某个时刻你突然全懂了,好像夜海航行中突然阳光普照...学业、工作、生活给人生的烦恼,都烟消云散。这个时刻是成长最重要的部分,他们说享受工作与生活的乐趣,就是从那个“开窍时刻”开始。”

  博客写到这个地步,已经不是为了找工作,享受过程才最重要。

——————————————————————————闲聊结束———————————————————————————

  第六章:接口与多态

  上一章聊过继承,提到“别滥用继承”,或者有人看到过“优先考虑接口而不是用继承”的说法。那么,什么样的情况叫滥用继承?接口又是什么东西呢?这一章,我们就来了解一下关于继承与多态的内容。

  第一节:接口定义行为

  如果我们要定义一个鲨鱼类,它会游泳,那么按照我们刚学过的继承,好像是可以定义一个鱼类作为父类,让鲨鱼类进行继承。到这里,是没有问题的,但,如果我们现在要定义一个Human(人)类,也会游泳,是不是又要继承鱼类呢?

1 Class Human extends Fish{
2 ...
3 }

  按照继承中“is-a”的说法,我们可以理解成“人是一种鱼”!o(╯□╰)o这显然是错误的。那么,有什么办法可以解决呢?下面,我们隆重推出interface(接口)这一概念。

  会游泳,我们可以定义成一种行为,或者一种能力。那么对于“定义行为”,在Java中可以使用interface关键字进行定义:

1 public interface Swimmer{
2     public abstract void swim();
3 }

  如果类要实现接口,必须使用implements关键字。在定义接口时,对接口中定义的方法有两种处理方式,一是操作接口中定义的方法,二是再度将该方法标示为abstract。

  第二节:接口与多态

  对比继承,我们可以写出这样的代码(在昨天的博客中有引用)——

1 Animal animal1=new Cat();
2 Animal animal2=new Dog();

  那么接口是否也可以进行这样的写法呢?答案是可以的。判断标准就是“右边是不是拥有左边的行为”,或者“右边对象是不是操作了左边接口”。接着说Human类和Fish类都实现了Swimmer接口,那么,我们可以这样写:

1 Swimmer swimmer1=new Human();
2 Swimmer swimmer2=new Fish();

  那么,既然说到多态,我们是如何使用的呢?看以下的代码,我们就可以用同一种写法,调用不同的方法:

 1 package cc.openhome;
 2 
 3 public class Ocean {
 4     public static void doSwim(Swimmer swimmer) {
 5         swimmer.swim();
 6     }
 7     
 8     public static void main(String[] args) {
 9         doSwim(new Anemonefish("尼莫"));
10         doSwim(new Shark("兰尼"));
11         doSwim(new Human("贾斯汀"));
12         doSwim(new Submarine("黄色一号"));
13     }
14 }

  第三节:接口的默认

  在Java中,在定义interface的时候,一定要把方法声明为publice abstract,不需要也不能进行方法内容的撰写。不过呢,为了方便,也可以省略public abstract。但是我们要清楚,接口里的方法都是公开(权限)并且是抽象的。

  下面看一道偶尔会出现的题目:

 1 interface Action{
 2     void execute();
 3 }
 4 
 5 class Some implements Action{
 6     void execute(){
 7         System.out.println("完成指定动作");
 8     }
 9 }
10  
11 public class Main{
12     public static void main(String[] args){
13         Action action=new Some();
14         action.execute();
15     }
16 }

  “请问执行结果如何?”答案是编译发生错误。为什么呢?因为Action中定义的execute()方法默认为public abstract,而Some类在操作execute()方法时,没有用public修饰,则默认为包权限,也就是说将Aciton中的public权限方法降权限为包权限,所以编译失败。所以大家在实现接口的时候就要注意了,记得是实现方法时加上public。

  另外,在接口中也可以定义public static final的枚举常数,跟定义方法一样,也可以省略public static final,但是在理解该“变量”时,一定要注意脑补加上“public static final”哟。

  第四节:匿名内部类

  在写Java程序的时,经常会有临时继承某个类或操作某个接口并建立实例的需求。由于这类子类或接口操作类只使用一次,不需要为这些类定义类名,这时可以使用匿名内部类(Anonymous inner class)来解决这个需求。匿名内部类的语法是这样的:

1 new 父类()|接口(){
2     //类本体操作
3 };

  如果是操作某个接口,例如若Some接口定义了doService()方法,要建立匿名类实例,可以这么写:

1 Some some = new Some(){   //操作Some接口并直接产生实例
2     public void doService(){
3         System.out.println("完成指定动作");
4     }
5 };

  说到匿名内部类,就不得不提一下内部类了。(本来想对比一下内部类和匿名内部类的区别的,但是一时没找到特别好的资料,先放放,等合适的时候再不上)

  第五节:使用enum枚举常数

  从JDK5之后就新增了enum语法,用来定义枚举常数。我们直接来看范例:

1 public enum Action{
2     STOP,RIGHT,LEFT,UP,DOWN
3 }

  实际上,enum定义了特殊的类,继承自java.lang.Enum,不过这是由编译程序处理,直接撰写程序继承Enum类是会被编译程序拒绝的。而enum中列举的常数,实际上也是public static final,而且是枚举类型的实例,程序员们是无法撰写程序直接实例化枚举类型的,因为构造函数的权限设定为private,只有在类里面才可以实例化。建议大家用反编译器对.class文件进行反编译,就可以看到里面的情况到底是怎样的。

  第七章:异常处理

  程序员最怕的不是写不出程序,而是在测试,甚至是生产环境下因为一些想都想不到的状况引发异常或者是错误。在Java中,错误也是以面向对象的方式呈现的,都是java.lang.Throwable的各种子类实例。我们可以通过捕捉(Catch)封装错误的对象,针对该错误作出应对,给出解决方案。例如,试图返回至正常的流程、进行日志(Logging)记录,或者是以某种形式作出提醒和警告。

  第一节:使用try、catch

  首先,我们来看一段简单的程序,就是我们可以从控制台连续输入整数,最后输入0结束后会显示输入数的平均值:

 1 package cc.openhome;
 2 
 3 import java.util.Scanner;
 4 
 5 public class Average {
 6     public static void main(String[] args) {
 7         Scanner scanner = new Scanner(System.in);
 8         double sum = 0;
 9         int count = 0;
10         int number;
11         while(true) {
12             number = scanner.nextInt();
13             if(number == 0) {
14                 break;
15             }
16             sum += number;
17             count++;
18         }
19         System.out.printf("平均 %.2f%n", sum / count);
20     }
21 }

  如果我正确地输入每个合法的数据,程序当然会跟我们预期的那样显示平均数,如图

  但是,总会有输错的时候,那结果会如何呢?例如我把50输成5p了,会怎样?

  看到错误的信息,以前的我一般都是挺沮丧的,因为自己写的程序出了问题嘛。但是,这段错误信息对于排除错误是很有价值的。根据提示的错误,例如图中的java.util.InputMismatchException。就是输入的内容,跟定义的数据类型不符合的意思。可是,如果用户是小白,看不懂这些信息呢?ok,我们可以用try-catch语句进行处理,给予小白用户看得懂的错误提示。看到以下代码:

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 public class Average2 {
 6 
 7     public static void main(String[] args) {
 8         try {
 9             Scanner scanner = new Scanner(System.in);
10             double sum = 0;
11             int count = 0;
12             int number;
13             while (true) {
14                 number = scanner.nextInt();
15                 if (number == 0) {
16                     break;
17                 }
18                 sum += number;
19                 count++;
20             }
21             System.out.printf("平均 %.2f%n", sum / count);
22         } catch (InputMismatchException ex) {
23             System.out.println("必须输入整数");
24         }
25     }
26 }

  跟上次一样,输入同样的内容,会怎样呢?

  第二节:异常继承架构

  刚才我们提到“在Java中,错误也是以面向对象的方式呈现的,都是java.lang.Throwable的各种子类实例”,那么,现在我们来看看Throwable继承架构图

  首先呢,我们要了解到错误都是会被封装为对象,设计这些错误对象都继承自java.lang.Throwable类,Throwable定义了取得错误信息以及堆栈错误(Stack Trace)等方法,它有两个子类:java.lang.Error与java.lang.Exception。

  Error与其子类实例代表严重系统错误,例如硬件层面的错误啦、JVM错误或内存不足等问题。虽然我们也可以用try-catch语句对这些对象进行捕获,但是这并不是被倡导的,因为发生严重系统错误的时,Java应用程序本身是无法回复的。举个例子,如果JVM所需要的内存不足,我们可以用语句要求操作系统给JVM分配更多的内存呢?所以,Error对象抛出时,基本上就不用处理,任其传播至JVM为止,最多也就是留下日志信息。

  而try-catch语句处理的错误基本上都是Exception或其子类实例,所以通常把错误处理称为异常处理(Exception handling),对于某些异常,可以用try、catch语法尝试将应用程序回到正常的轨道上(可执行状态)。值得注意的是,如果某个方法声明会抛出Throwable、Exception或子类实例,但又不属于java.lang.RuntimeException或其子类实例,就必须明确使用try-catch语法加以处理,或者用throws声明这个方法会抛出异常,否则就会发生编译错误。

  Exception或其子对象,但不属于RuntimeException或其子对象,成为受检异常(Checked Exception)。受检,指的是受编译程序检查。API设计者认定,调用这个方法时,出错的几率极高,因此要求编译程序协助提醒调用API的用户明确使用语法处理,程序员无法选择要不要进行处理。与之相反的,就是非受检异常(Unchecked Exception)。

 

  由于明天有个面试,今晚还是要复习准备一下的,所以第七章《异常处理》就先写到这里,明天再继续。其实今天的内容已经比之前多一点点了,慢慢来。

———————————————————————————第18天——————————————————————————

  其实,我曾经是一个文艺少年。

1.我高中在广东深圳念的书,哪怕到了高三,也不觉得有多么紧张。不像北方的某些省份那么恐怖,听说有些学校的高三学生早上五点多起床,一直学习到晚上十一点多,几乎没有多少自己的时间。

2.在高三刚开始的时候,我突然迷上了看课外书,村上春树的小说,梁文道《常识》、《读者》,好多虚构类的文学作品,好多非虚构类的书籍,大半年下来大概在卓越亚马逊花了两千多块钱。语文突然好了起来,作文尤其写得不错,模拟考经常考第一。其他的科目也有所稳定提升,我想,大概是看书让我的内心平静了下来。上了大学,看书的频率骤然降低,也几乎很少写东西了。写到这里,我突然明白,明白自己为什么迷茫了那么一段时间。也许是因为大学的诱惑多了,不再有那么多的耐心坐下来看书做读书笔记了。最近自制力开始有点上来了,又重拾了阅读(虽然是从课外书转变到技术书)和写作的乐趣,用自己的方法,按照自己的节奏,一点一点地进步。

3.也许,这就是成长的代价

posted @ 2013-11-05 22:50  LevenYes  阅读(831)  评论(4编辑  收藏  举报