首页 > 代码库 > JAVA面向对象

JAVA面向对象

Java 面向对象

一、        前言

1.      理解面向对象

  • 面向对象是相对面向过程而言
  • 面向过程强调的是功能行为
  • 面向对象将功能封装进对象,强调具备了功能的对象。
  • 开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情。
  • 设计的过程:其实就是在管理和维护对象之间的关系。
  • 封装(encapsulation)
  • 继承(inheritance)
  • 多态(polymorphism)
  • 类:是具有相同属性和方法的一组对象的集合。
  • 对象:用来描述客观事物的一个实体,由属性和方法构成。
  • 类是对象的抽象,对象是类的具体实例。
  • 类是抽象的,不占用内存,而对象是具体的,占有内存空间。

2.      面向对象的特点

二、        类和对象

1.     类和对象的定义

Public class ConstructorMethod {

String name;

Int age;// 成员变量

Public ConstructorMethod(String name, int age) {

//有参构造方法,构造方法无返回类型

this.name = name;

this.age = age;//实例的属性 = 实参;

}

Publicstaticint Case1() {//成员方法

System.out.println("我是Case1调用");

return0;

    }

}

2.     类的创建和使用

a)     类的定义

  • 访问修饰符 class 类名 {成员变量;成员方法}      // 详见上例
  • 引用类的属性:对象名.属性

b)     类的使用

举例:center.name = "北京中心";     //给name属性赋值

  • 引用类的方法:对象名.方法名()

举例:center.showCenter();     //调用showCenter()方法

c)     补充说明

  • 在Java中,类是按须加载,只有当需要用到这个类的时候,才会加载这个类,并且只会加载一次。
  • 一个类文件中Public类只有一个,且和类文件同名。且类的访问权限只有Public和Default,包内均可见,故包内类不可同名。
  • 类名 对象名= new 类名();

3.     对象的创建和使用

a)     对象的创建

举例:School center = new School();

b)     对象的使用

  • 用对象名引用类的属性和方法。参见类的使用。
  • 类名 对象名= new 类名();        //对象的声明与初始化
  • 数据类型 变量名 = new 数据类型(值);       //变量的声明与初始化
  • 对象名和变量名都是一种引用。数据类型可以当做一种特殊的类。在此概念下,变量和对象的特性可部分通用。
  • 成员变量:在类的范围内声明,在类的整个范围内都能用,类似C语言中全局变量
  • 局部变量:在局部(方法体内)声明,大括号(或循环体)限制局部变量的作用域。
  • 数据类型 变量名 = 值;或 数据类型 变量名 = new 数据类型(值);
  • 第二种声明方式一般不用,本文引入主要是为了与对象的定义进行对比。
  • 局部变量在使用前必须赋初始值。成员变量即使没有赋初始值,系统会自动初始化,

d)     对象和变量的几点思考

4.     成员变量VS局部变量

a)     定义

b)     变量的声明与初始化

c)     使用规则

基本数据类型为初始化为0,布尔类型为false,引用类型为null。

  • 局部变量和成员变量可以同名,同名时,就近使用。
  • Java没有全局变量的概念。概念相近的有静态变量。

publicclassTest {

publicstaticvoidmain(String[] args) {

    Catcat = null;  //局部变量需要初始化或传实参

    Petpet = newCat();

    cat = (Cat)cat;

    }

}

 

classPet {

}

 

classCatextendsPet {

}

5.     成员方法VS方法

a)     定义

  • 所谓方法,就是可以重复使用的一段代码的组合,是一个功能模块。成员方法是定义在类内部的方法。

一般格式:访问修复符 返回值类型 方法名(参数列表){方法体};

  • 访问修饰符:方法允许被访问的权限范围, 可以是 public、protected、private 甚至可以省略。
  • 返回值类型:方法返回值的类型。如果方法不返回任何值,则returnValueType的值为 void ;如果方法返回值不为void,则需要指定返回值的类型,并且在方法体中使用 return 语句返回值。
  • 方法名:定义的方法的名字,必须使用合法的标识符
  • 参数列表:传递给方法的参数列表,参数可以有多个,多个参数间以逗号隔开,每个参数由参数类型和参数名组成,以空格隔开。定义时的参数成为形参,须定义数据类型。调用时的参数称为实参,实参不用定义数据类型。
  • 方法体:方法体包含定义哪些方法语句的集合。
  • 语句语句必须写在方法体内,除初始化语句。

b)     访问修饰符

类的访问权限有Public和Default两种,类中成员的访问权限有下列四种:

  • Public: 能访问该类的任何地方可以访问Public成员。
  • Protected:(子类修饰符)包内,和包外自身从父类继承而来的受保护成员。
  • Default:(包修饰符)包内成员可相互访问。
  • Private:(私有修饰符)只有自己类内的成员可以访问。
  • 访问权限由大到小:public>protected>default>private
 
   


补充:继承权限测试.Package

继承权限测试(类之间)  & 访问权限测试(属性和方法)测试结果:

  • 访问修饰符是限制要访问(继承)自己的对象权限的符号
  • 应用范围:

类的访问修饰符只有public和默认两种。

类中成员 public(公共修饰符) --> protected(子类) --> default()--> private(私有)

局部变量作用域确定,故没有访问修饰符,访问修饰符仅针对成员变量和方法。

  • 访问方式:

子类对父类的访问,直接调用属性或方法(其实隐含this.调用)

 非继承关系或父类对子类的访问的访问方式,需用对象或类名访问。

  • 应用原理:

访问权限是基于继承决定的,继承权限也是一种访问权限。

继承则属性和方法归父类和子类共有,但除私有成员不可以访问。

子类可以选择重写父类的属性和方法的访问修饰符,权限不能小于父类

c)     方法的调用

  • 在同一个包里,普通方法需要用对象名调用,静态(类)方法可以直接类名调用(同一类甚至不用写类名)。

d)     方法的重载

方法重载,就是在同一个类里中可以创建多个方法,方法名要一样,参数列表不同,和访问修饰符 、返回值无关。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法,是一个类中多态性的一种表现。

方法重写,在子类和父类之间对,父类的函数进行重新定义。子类名称和参数别表与父类相同,方法体重写。

6.     构造方法

所谓构造方法,就是构造对象的方法,通过new + 构造方法, 这样就创建了一个新的对象。

  • 构造方法要与类名相同,无返回类型。在创建对象的时候,对象的属性进行初始化,减少初始化语句。
  • 每一个类都有构造方法,在没有定义时,系统默认创建一个无参构造方法。
  • 构造方法是一类特殊的方法,在定义和调用具有普通方法的特性。
  • 成员变量包括实例变量和类(静态)变量;而成员方法包括实例方法、类(静态)方法。
  • 类变量、类方法是属于类的变量、方法,必须是静态的,要加static;故其又称静态变量、静态方法。可以不用实例,直接用类就可以访问或调用类变量或类方法。
  • 实例变量和实例方法在一个类中没有static修饰,使用变量或方法时候先实例化(创建对象)才能访问或调用实例变量或实例方法;
  • 方法与变量是个总体性概念,定义在类内部的被称为成员变量与成员方法,定义在main方法或方法体内部的变量被称为局部变量。
  • 实例方法引用this指向正在执行方法的类的实例,构造方法引用this指正在的构造对象,静态方法不能使用this和supper关键字,构造方法根据不同参数指向类的实例。
  • super()或者this()都是调用构造函数,构造函数用于初始化,所以初始化的动作要先完成。
  • super()super. 只能在子类里使用。

7.     补充几点

a)     变量几个概念的解析

b)     this和supper的用法

publicclassTest {

    privateStringname;

    publicTest(){

       this.name = "小新";

    }

    publicTest(Stringname) {

       System.out.println("我是" +this.name);

    }

    publicstaticvoidmain(String[] args) {

       Testtest = newTest("小强");

    }

}//运行结果:我是null(实参没有该成员变量赋值)

c)     main 方法

publicclassTest {

publicstaticvoidmain(String[] args) {

    for (inti = 0; i<args.length; i++) {

    System.out.println("args" + i + "=" + args[i]);

    }

    }

}

输出结果:

args0=args1

args1=args2

  • Public:表示的这个程序的访问权限,表示的是任何的场合可以被引用,这样java虚拟机就可以找到main()方法,从而来运行javac程序。
  • Static:表明方法是静态的,不依赖类的对象的,是属于类的,在类加载的时候main()方法也随着加载到内存中去。如果主函数设置成非静态,则无法运行。或实例化主方法。
  • Void:main()方法是不需要返回值的。
  • Main:作为程序的入口,有main方法程序才能运行。
  • args[]:是用来从控制台接收参数。
  • 静态方法内不可以调用非静态属性,若要调用非静态成员属性,则需要把属性设置成静态属性。或者把把非静态成员单独封装成方法,再通过方法调用
  • 方法体内部只可定义语句,不可再定义方法。
  • 参数的声明
  • 接收实参的几种形式

d)     方法传参

u  intmonth = 4;

u  intday = input.nextInt();

注:作为形参的变量的初始化便是传入实参。

 

待补充~

e)     内部类

内部类将相关的类组织在一起,从而降低了命名空间的混乱。一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分。内部类可以直接访问外部类中的成员。而外部类想要访问内部类,必须要建立内部类的对象。

  • Java 内部类种类及使用解析  http://www.cnblogs.com/mengdd/archive/2013/02/08/2909307.html

http://blog.sina.com.cn/s/blog_accab4a90101gzh2.html

①    匿名内部类

匿名内部类也就是没有名字的内部类,正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。

abstractclassPerson {

publicabstractvoideat();

}

 

publicclassDemo {

publicstaticvoidmain(String[] args) {

    Personp = newPerson() {

    publicvoideat() {

       System.out.println("eat something");

        }

    };

    p.eat();

    }

}

a)      Static关键字

  • 想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。
  • 被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态方式。
  • 静态随着类的加载而加载。而且优先于对象存在。
①    静态代码块

一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只被执行一次,静态块常用来执行类属性的初始化。

    static {

    System.out.println ("Hello Everyone");

        }

方法里不可以定义static

待补充~

b)     final关键字

这个关键字是一个修饰符,可以修饰类,方法,变量。

  • 被final修饰的类是一个最终类,不可以被继承。
  • 被final修饰的方法是一个最终方法,不可以被覆盖(重写)。
  • 被final修饰的变量是一个常量,只能赋值一次。

三、      封装、继承和多态

1.     封装

publicclassTest {

    privateStringname;//将类的属性进行封装

publicStringgetName() {//并提供可带判断条件的访问方法

returnname;

}

 

publicvoidsetName(Stringname) {

this.name = name;

}

}

 

a)     定义

将类的属性隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

b)     步骤

修改属性的可见性(设为private,防止错误的修改)à创建公有的getter/setter方法(用于属性的读写)à在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)。

c)     优点

  • 封装确实可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码。
  • 可以对成员变量进行更精确的控制。
  • 限制对属性的不合理操作;
  • 结合权限控制,限制客户端的操作权限。

2.     继承

classPerson {                     // 父类

privateStringname;

publicstaticintage;

publicstaticStringsex;

 

publicPerson() {              // 会自动生成无参构造器

System.out.println("父类构造器");                        

    };                           // 但是考虑继承的可靠性,建议写上。

 

publicvoidsetName(Stringname) {

this.name = name;

    }

 

publicStringgetName() {

returnthis.name;

    }

}

 

classStudentextendsPerson {   // 子类

privateStringschool;

 

publicStudent() {          // 子类student中构造

super();                //super只可在子类中使用

System.out.println("子类构造器");

    }

}

publicclassTestExtendDemo {// 测试类

publicstaticvoidmain(String[] args) {

Person.age = 18;

Student.age = 19;         // 继承父类的成员属性和方法可直接调用

Person.sex = "男";        // 静态变量或方法用类调用

System.out.println(Student.age+Person.sex);

Scannerinput = newScanner(System.in);

Studentsomeone = newStudent();    //创建子类对象的过程

someone.setName(input.next());      // 实例变量和方法用实例调用

System.out.println(someone.getName());

    }

}

a)     定义

继承是面向对象最显著的一个特性。多个类中存在相同属性和方法时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和方法,只要继承那个类即可。继承是代码重用的一种方式。Java通过extends关键字来实现单继承。(Is a)

b)     继承的基本原则

  • 能够继承除构造方法外所有成员,但private成员不可以访问;
  • 可以同通过super()调用类的构造方法,已提高代码重用性。同样super()可以调用父类的成员属性和成员方法。
  • Java具有单根继承性,只能继承一个父类。
  • Java继承具有传递性,支持多级继承。
  • Object类是所有类的父类。
  • 声明:[访问修饰符] class Dog extendsPet {   //子类特有的属性和方法}
  • 调用父类构造方法:super(); super(name);

c)     格式与引用

访问父类属性:super.name;

调用父类方法:super.print();

d)     补充几点

  • 父类没有无参构造器,则需在子类构造器的第一行显式调用父类的有参构造器。

原因:子类的所有构造器中的第一行,其实都有一条隐身的语句super(), super()表示调用父类的无参构造器。子类继承父类中的属性,在new 子类的时候,相应的父类的属性也就拿到了,这就是子类的实例化过程。

然而父类有有参构造器,则无参构造器就不存在了,所以在子类中须在第一行显式调用super(参数),或者在父类中添加一个无参构造器。之所以须在第一行调用,是因为父类的构造器调用以及初始化过程一定在子类的前面。

并且,父类也被new一个对象出来的说法是错误的,举例抽象类可以被继承的,但抽象类不能被实例化。

  • 隐藏和覆盖的区别:

参考:Java中属性的隐藏与方法的覆盖的区别

参考:静态绑定与动态绑定

  • 方法重写的原则:

u  子类方法重写时方法名、参数、返回值、返回类型均须相同。访问权限不小于父类。

解析:确保子类可以重写父类。父类不能覆盖子类。

u  重写是父子类要么都静态,要么都不静态。

u  子类可以定义与父类同名的静态方法,以便在子类中隐藏父类的静态方法。

u  父类的私有方法不可访问,不能被子类重写。

 

3.     多态

abstractclassAnimal {// 因为本身实例化没有意义,所以一般申明为抽象类

Animal() {        // 会自动生成无参构造器

    };                  // 但是考虑继承的可靠性,建议写上。

 

abstractvoideat();//  抽象方法

}

classCatextendsAnimal {      // 1、继承父类

publicvoideat() {         // 2、子类方法的重写

System.out.println("吃鱼");

    }

 

publicvoidcatchMouse() {  //子类私有方法,只能用子类对象调用

System.out.println("抓老鼠");

    }

}

 

classDogextendsAnimal {       // 1、继承父类

publicvoideat() {          // 2、子类方法的重写

System.out.println("吃骨头");

    }

 

publicvoidkanJia() {

System.out.println("看家");

    }

}

 

classDuoTaiDemo {                // 类名与源文件相同,否则无法运行

publicstaticvoidmain(String[] args) {

function(newCat());      // new Cat() 表示构造一个猫的对象

function(newDog());

 

//Animal a;//对象可像变量一样声明和传递参数

        //a= new Cat();     //父类为抽象类,不能实例化,但能创建引用

        Animala=newCat();

        // 向上转型 // 类似变量传参,new Cat()是参数

a.eat();

        //3.父类对象引用指向子类对象 PS:须先满足前两个条件

    }

 

publicstaticvoidfunction(Animala) {//对象可作变量传递参数

a.eat();       //3.父类对象引用指向子类对象 PS:须先满足前两个条件

 

if (ainstanceofCat) {// 用于判断对象是否为指定类的实例

Catc = (Cat) a;    // 向下转型,由Animal(父)类转为Cat(子)类

c.catchMouse();// 向下转型,调用子类特有属性

        } elseif (ainstanceofDog) {

Dogc = (Dog) a;

c.kanJia();

        }

    }

 

publicclassPolymorphism {// 多态传参 ,取例 Think in Java

Void doStuff(Shapes) {// 形参

    s.erase();

    // ...

    s.draw();

    }

 

Public static void main(String[] args) {

 

    Circle c = new Circle();// Circle/Triangle/Line是Shape的子类

    Triangle t = new Triangle();

    Line l = new Line();

    doStuff(c);// 实参

    doStuff(t);

    doStuff(l);

    }

}

a)     定义

指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是方法调用),与方法不同的是对象的属性则不具有多态性。

b)     实现技术

动态绑定:是指在程序运行时判断所引用对象的实际类型,根据其实际的类型调用其相应的方法,是多态实现的具体形式。执行动态绑定的非静态方法

补充知识:静态绑定:又称为前期绑定在程序编译时进行了绑定,即在还没运行时,就已经加载到内存。执行静态绑定的有变量和静态方法

c)     必要条件

  • 要有继承(实现多态的前提);
  • 要有重写(实现多态的基础);
  • 父类引用指向子类对象

d)     实现方式

接口实现,继承父类进行方法重写,同一个类中进行方法重载。当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的该同名方法。

e)     作用

消除类型之间的耦合关系

f)      补充几点

  • 多态在子父类中的成员上的体现的特点:(待进一步完善)

u  成员变量:在多态中,子父类成员变量同名。

在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误)

运行时期:也是参考引用型变量所属的类中是否有调用的成员。

简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。再说的更容易记忆一些:成员变量à编译运行都看 = 左边。

u  静态函数

编译时期:参考的是引用型变量所属的类中是否有调用的成员。

运行时期:也是参考引用型变量所属的类中是否有调用的成员。

为什么是这样的呢?因为静态方法,其实不属于对象,而是所属于该方法所在的类。

调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。

简单说:静态函数à编译运行都看 = 左边。

u  成员函数

编译时期:参考引用型变量所属的类中是否有调用的方法。

运行事情:参考的是对象所属的类中是否有调用的方法。

为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。

简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。

更简单:成员函数à编译看 = 左边,运行看 = 右边。

 

四、      抽象类和接口

1.     抽象类(abstract)

publicabstractclassClassName {

    int name;

abstractvoidfun();

}

a)     定义

  • 抽象类:被定义为抽象的类,它用来集合子类的通用特性的。不能被实例化,只能被用作子类的超类。
  • 抽象方法:它只有声明,而没有具体的实现,如果一个类含有抽象方法,则称这个类为抽象类。抽象方法声明格式为:abstract void fun();因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。
  • 抽象类就是为了继承而存在的,如果定义一个抽象类,不去继承它,没有任何意义。
  • 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
  • 抽象类可以没有抽象方法,也可以全部是抽象方法,如果子类继承的父类是抽象类,则继承父类所有非私有方法,又由于存在抽象类的方法为抽象方法,故子类必须重写父类里所有的抽象的方法(除非父类抽象类没有抽象方法),才能被实例化,也就是创建对象,要不然子类也将是个abstract类,不能被实例化。
  • 抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用。

b)     特点

2.     接口(interface)

publicinterfaceInterfaceName {

    public abstractvoid cry();

}

    classClassNameimplementsInterface1,Interface2....{

}

a)     定义

在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。

接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。

接口主要用来描述类具有什么功能,自身不能做任何事情。具体实现交由实现接口的那个类来完成。

b)     特点

  • 接口中可以声明变量,且被隐式地指定为public static final变量。可当做全局常量用。
  • 接口是对方法的抽象,定义的方法必须是抽象方法。系统默认都是public abstract
  • 接口不可以实例化。
  • 实现类且必须实现所有的接口。如果不能全部实现,则定义两个接口。
  • 接口也可以extends接口
  • 接口回调:是指可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。     参考:http://blog.csdn.net/hack_bug/article/details/7625646
  • 如果需要从子类向基类进行向上转型,则使用基类,否则可使用组合关联。
  • 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
  • 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

c)     其他几点补充

d)     什么时候使用抽象类和接口

3.     抽象类和接口的对比

a)     语法层面的区别

参数

抽象类

接口

默认的方法实现

它可以有默认的方法实现

所有的方法都是抽象的。不存在方法的实现

实现

子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。

子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现

构造器

抽象类有构造器,用于子类初始化

接口不能有构造器

普通类

除了不能实例化抽象类之外,它和普通Java类没有任何区别

接口是完全不同的类型

访问修饰符

抽象方法可以有public、protected和default这些修饰符

接口方法默认修饰符是public。不可以使用其它修饰符。

main方法

抽象方法可以有main方法并且我们可以运行它

接口没有main方法,因此我们不能运行它。

多继承

抽象方法可以继承一个类和实现多个接口

接口只可以继承一个或多个其它接口

速度

它比接口速度要快

接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

添加新方法

如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。

如果你往接口中添加方法,那么你必须改变实现该接口的类。

b)     设计层面上的区别

抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

五、     

 
   


异常

1.     JAVA异常

Java异常处理的目的是提高程序的健壮性。你可以在catch和finally代码块中给程序一个修正机会,使得程序不因不可控制的异常而影响程序的流程。同时,通过获取Java异常信息,也为程序的开发维护提供了方便。

a)     概念解析

  • Java中的异常用对象来表示。
  • Java异常处理通过5个关键字try、catch、throw、throws、finally进行管理。
  • 异常是针对方法来说的,抛出、声明抛出、捕获和处理异常都是在方法中进行的。
  • Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。
  • Error(错误):表示仅靠程序本身无法恢复的严重错误。
  • Exception(异常):表示程序本身可以处理的异常。
  • RuntimeException:是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。Java编译器不去检查它。这种异常可以通过改进代码实现来避免。
  • ThreadDeath:
  • 运行时异常:

b)     运行时异常和受检查异常

RuntimeException类及其子类都被称为运行时异常,这种异常的特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try...catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过。

  • 受检查异常:

除了RuntimeException类及其子类外,其他的Exception类及其子类都属于受检查异常,这种异常的特点是要么用try...catch捕获处理,要么用throws语句声明抛出,否则编译不会通过。

  • 两者的区别

运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误的操作。

受检查异常表示程序可以处理的异常。受检查异常表示程序可以处理的异常。如果抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。

当然,这两种异常都是可以通过程序来捕获并处理的,比如除数为零的运行时异常。

2.     处理异常机制

异常处理机制为:抛出异常,捕捉异常。

  • 捕捉异常:在方法中用try...catch语句捕获并处理异常,catach语句可以有多个,用来匹配多个异常。
  • 抛出异常:对于处理不了的异常或者要转型的异常,在方法的声明处通过throws语句抛出异常。
  • Java规定:对于所有的可查异常,一个方法必须捕捉,或者声明抛出方法之外。

3.     捕获异常try / catch 和 finally

import java.util.InputMismatchException;

import java.util.Scanner;

 

publicclassTryCatch {

publicstaticvoidmain(String[] args) {

    Scannerinput = newScanner(System.in);

 

    try {// 可能会发生异常的程序代码

    System.out.print("请输入一个数字:");

    inta = input.nextInt();

    } catch (InputMismatchExceptione) {// 捕捉异常

    System.err.println("数据类型不符!");

    e.printStackTrace();

    System.err.println(e.getMessage());

    // return; 若捕捉到异常会先执行finally, 再return。

    } catch (Exceptione) {// catch 先写子类,再写父类

    System.out.println("再捕捉一次!");

    System.exit(1);

    } finally {// 除非执行System.exit(1),否则都会执行

    System.out.println("finally 被执行!");

    // 应用举例:确保关闭数据库,关闭流

    }

 

    System.out.println("我还是被执行了!");

    // 如果提前return,则不执行了

    }

}

4.     抛出异常 throws和throw

publicclassThrows {

 

publicstaticvoidmain(String[] args) throws Exception{

    System.out.println(10 / 0);

    thrownewException("抛出异常");

    //System.out.println("throw后面的代码不再执行");

    }

}

5.     Java常见异常

a)     runtimeException子类:

  • java.lang.ArrayIndexOutOfBoundsException

数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

  • java.lang.ArithmeticException

算术条件异常。譬如:整数除零等。

  • java.lang.NullPointerException

空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等

  • java.lang.ClassNotFoundException

找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

  • java.lang.NegativeArraySizeException数组长度为负异常
  • java.lang.ArrayStoreException数组中包含不兼容的值抛出的异常
  • java.lang.SecurityException安全性异常
  • java.lang.IllegalArgumentException非法参数异常
  • IOException操作输入流和输出流时可能出现的异常。
  • EOFException文件已结束异常
  • FileNotFoundException文件未找到异常
  • ClassCastException类型转换异常类
  • ArrayStoreException数组中包含不兼容的值抛出的异常
  • SQLException操作数据库异常类
  • NoSuchFieldException字段未找到异常
  • NoSuchMethodException方法未找到抛出的异常
  • NumberFormatException字符串转换为数字抛出的异常
  • StringIndexOutOfBoundsException字符串索引超出范围抛出的异常
  • IllegalAccessException不允许访问某类异常
  • InstantiationException当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常

b)     IOException

c)     其他

6.     自定义异常

待补充~

7.     Java异常处理的原则和技巧

  • 避免过大的try块。
  • 不要把自己能处理的异常抛给别人。
  • catch块尽量保持一个块捕获一类异常
  • 细化异常的类型,不要不管什么类型的异常都写成Excetpion。
  • 不要用try...catch参与控制程序流程,异常控制的根本目的是处理程序的非正常情况。

8.     补充几点

如果出现异常的线程为主线程,则整个程序运行终止;如果非主线程,则终止该线程,其他线程继续运行。

如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的,如果子类的覆盖的方法中出现了异常,只能try不能throws。

如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通过throw抛出RuntimeException异常或者其子类,这样,子类的方法上是不需要throws声明的。

越早处理异常消耗的资源和时间越小,产生影响的范围也越小。

JAVA面向对象