面向对象思想的主要体现:
面向对象:将功能封装进对象,强调具备了功能的对象。
面向对象的特点:
1、是一种符合人们思考习惯的思想
2、可以将复杂的事情简单化
3、将程序员从执行者转换成了指挥者
4、完成需求时:先要去找具有所需的功能的对象来用。如果该对象不存在,那么创建一个具有所需功能的对象。这样简化开发并提高复用。
开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情。
设计的过程:其实就是在管理和维护对象之间的关系。
java中描述事物通过类的形式体现,类是具体事物的抽象,概念上的定义。对象即是该类事物实实在在存在的个体。
成员变量:成员变量定义在类中,在整个类中都可以被访问。成员变量随着对象的建立而建立,存在于对象所在的堆内存中。成员变量有默认初始化值。
局部变量:局部变量只定义在局部范围内,如:函数内,语句内等。局部变量存在于栈内存中。作用的范围结束,变量空间会自动释放。局部变量没有默认初始化值。
主函数的定义:
Public:代表着该函数的访问权限是最大的。
Static:代表主函数随着类的加载就已经存在了。
Void:主函数没有具体的返回值。
Main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
(string[] ags):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。
主函数是固定格式的:jvm识别。
Jvm在调用主函数时,传入的是now string[0];
匿名对象使用方式一:当对对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化。(如果对一个对象进行多个成员调用,必须给这个对象起个名字。)
匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
封装好处:
1、将变化隔离。
2、便于使用。
3、提高重用性。
4、提高安全性。
封装原则:将不需要对外提供的内容都隐藏起来。把属性都隐藏,提供公共方法对其访问。
private关键字:是一个权限修饰符。用于修饰成员(成员变量和成员函数),被私有化的成员只在本类中有效。
常用之一:将成员变量私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全
面向对象(静态什么时候使用)
要从两方面下手:
因为静态修饰的内容有成员变量和函数。
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态所修饰。
对象中的特有数据要定义成非静态存在于堆内存中。
什么时候定义静态函数呢?当功能(函数)内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。
面向对象(静态的应用-工具类)
静态的应用
每一个应用程序中都有共性的功能,
可以将这些功能进行抽取,独立封装。(静态)以便复用。
虽然可以通过建立Arraytool的对象使用这些工具方法,对数组进行操作。发现了问题:
1,对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
2,操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
这时就考虑,让程序更严谨,是不需要对象的。
可以将ArrayTool中的方法都定义成static的。直接通过类名调用即可。
将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。
为了更严谨,强制让该类不能建立对象。
可以通过将构造函数私有化完成。
还有些方法只对内起作用,不对外起作用,也可将此方法私有化。
面向对象(帮助文档的制作javadoc)
set classpath=.;c:\myclass(.;代表当前文件夹,作用是文件不在同一个文件夹使用。)
类需要有public修饰才能被说明为帮助文档。
一个类中默认会有一个空参数的构造函数。
这个默认的构造函数的权限和所属类一致。
这个类被public修饰,那么默认的构造函数,也有public修饰。
如果构造函数被定义,就无默认构造函数。
面向对象(静态代码块)
格式:
Static
{
静态代码块中的执行语句。
}
特点:随着类的加载而执行,只执行一次(再次建立不执行),并优先于主函数运行。构造代码块的优先级比构造函数高。
面向对象(对象的初始化过程)
构造代码块的优先级比构造函数高。
先是默认初始化,然后是显示初始化,紧跟是构造代码块初始化,接下来是构造函数初始化。
person p=new person("zhangsan",20);
该句话都做了什么事?
1,因为new用到了person.class.所以会先找到person.class。
2,执行该类中的static代码块,如果有的话,给person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对特有属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的P不变量。
9,因为不涉及静态方法调用,所以静态方法没有初始化。(静态方法只在调用是初始化)
面向对象(单例设计模式)
设计模式:(解决问题最行之有效的方法。完全偏思想,不仅JAVA可以用。)
JAVA中有23种设计模式:其中一种:单例设计模式:解决一个类在内存中只存在一个对象。(要保证对象在内存中的唯一性)
想要保证对象唯一:
1,为了避免其它程序过多建立该对象。先禁止其它程序建立该对象。
2,还为了其他程序程序可以访问到该对象,只好在本类中,自定义一个对象。
3,为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三步怎么用代码体现呢?
1,将构造函数私有化。
2,在类中创建一个本类对象。
3,提供一个方法可以获取到该对象。
对于事物该怎么描述,还怎么描述。
当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
面向对象(继承-概述)
类本身就是一种抽象。
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行 为,只要继承单独的那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。子类可以直接访问父类中的非私有的属性和行为。通过extends 关键字让类与类之间产生继承关系。class SubDemo extends Demo{}
被继承的为父类,提高代码的复用性,继承让类与类之间产生关系,有了这个关系,才有了多态的特性。
注意:
1、千万不要为了获取其它类的功能,简化代码而继承。
2、类与类之间要有所属( " is a " )关系,xx1是xx2的一种。
如果父类中有的功能不是子类应该具备的,就不是继承。
JAVA语言中:只支持单继承,不支持多继承。
因为多继承容易带来安全隐患:因为当多个父亲中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。
但是JAVA保留这种机制,并用另一种体现形式来完成表示。多层实现。
Java支持多层继承,也就是一个继承体系。
如何使用一个继承体系中的功能呢?
想要使用体系,先查阅体系父亲的描述,因为父类中定义的是该体系中共性功能。
通过了解共性功能,就可以知道该体系的基本功能。
那么这个体系已经可以基本使用了。
那么在具体调用时,要创建子类的对象,为什么呢?
一、是因为有可能父类不能创建对象。
二、是创建子类对象可以使用更多的功能,包括基本的也包括特有的。
简单一句话:查阅父类功能,创建子类对象使用功能。(一个孩子只能有一个父亲)
面向对象(聚集关系)
聚合(聚集):指的是整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构。从而找出一些组成类,该整体类和组成类之间就形成了聚合关系。
组合:也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在。部分对象与整体对象之间具有共生死的关系。
聚合和组合的区别在于:
聚合关系是“has-a”关系,组合关系是“contains-a”关系;
聚合关系表示整体与部分的关系比较弱,而组合比较强;
聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。
聚合∶分散的聚集到一起。
组合:几个独立部分组成的整体,事物的联系关系更紧密。(按照事物的紧密程度进行单独的划分)
面向对象(子父类中变量的特点)
子父类出现后,类成员的特点:
类中成员:
1.变量。
2,函数。
3,构造函数。
1,变量
如果子类中出现非私有的同名成员变量时,
子类要访问本类中的变量,用this
子类要访问父类中的同名变量,用super。
super 的使用和this的使用几乎一致。
this代表的是本类对象的引用。
面向对象(子父类中函数的特点-覆盖)
修改源码绝对是灾难。
子父类中的函数。
当子类出现和父类一模一样的函数时。
当子类对象调用该函数,会运行子类函数的内容。
如同父类的函数被覆盖一样。
这种情况是函数的另一个特性:重写(覆盖)
当子类继承父类,沿袭了父类的功能,到子类中,
但是子类虽具备该功能,但是功能的内容却和父类不一致,
这时,没有必要定义新功能,而是使用覆盖特殊,保留父类的功能定义,并重写功能内容。
写覆盖注意:
1、子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
2、静态只能覆盖静态。
默认(什么都不写)权限在public与private之间。
重载:只看同名函数的参数列表。
重写:子父类方法要一模一样。
面向对象(子父类中构造函数的特点-子类实例化过程)
子父类中的构造函数。
在对子类对象进行初始化时,父类的构造函数也会运行。那是因为子类的构造函数里默认第一行有一条隐式的语句supper();
supper():会访问父类中空参数的构造函数。而且子类中所有的构造函数里默认第一行都是super();
为什么子类一定要访问父类中的构造函数?
因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要首先看父类是如何对这些数据进行初始化的。
所以子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
注意:super语句一定定义在子类构造函数里的第一行。
构造函数里面要么只能有this语句(都要在第一行)要么只能有super语句(都要在第一行)
为什么都要在第一行:初始化动作要先做。
super()你调用父类的构造方法,为什么要调用父类的构造方法呢?那是因为子类继承了父类,获取到了父类中内容(属性),所以在父类内容之前,要先看父类是如何对自己的内容进行初始化的,所以子类在构造对象时,必须访问父类中的构造函数,this() 调用子类中其他的构造方法给对象初始化,就是间接的访问了父类的构造方法this()和super()不能同时出现在一个构造函数里面,因为this()必然会调用其它的构造函数,其它的构造函数必然也会有super()语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
子类的实例化过程。
结论:子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super():
当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
子类实例化过程:
1.分配成员变量的存储空间并进行默认的初始化,就是用new关键字产生对象后,对类中的成员变量按第三章的表3.1中的对应关系对对象中的成员变量进行初始化赋值。
2.绑定构造方法参数,就是new Person(实际参数列表)中所传递进的参数赋值给构造方法中的形式参数变量。
3.如有this()调用,则调用相应的重载构造方法(被调用的重载构造方法又从步骤2开始执行这些流程),被调用的重载构造方法的执行流程结束后,回到当前构造方法,当前构造方法直接跳转到步骤6执行
4.显式或隐式追溯调用父类的构造方法(一直到Object类为止,Object是所有Java类的最顶层父类,在本章后面部分有详细讲解),父类的构造方法又从步骤2开始对父类执行这些流程,父类的构造方法的执行流程结束后,回到当前构造方法,当前构造方法继续往下执行。
5.进行实例变量的显式初始化操作,也就是执行在定义成员变量时就对其进行赋值的语句,如:
6.执行当前构造方法的方法体中的程序代码 。
如下实例描述:
class X {
Y b = new Y();//执行Y的构造函数然后返回,接着返回b,执行完X构造方法里的语句后返回a处,但仍然先初始化成员变量y
X() {//b 先对成员变量显式初始化,而Y类型的b也算作是成员变量,所以跳到c
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
int i=0;
Z() {//a 执行上述描述的1,2步后执行第四步跳到b
System.out.print("Z");
}
public static void main(String[] args) {
new Z();//产生z的实例跳到a
}
}
面向对象(final关键字)
final:
1,可以修饰类,函数,变量。
2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。
3,被final修饰的方法不可以被复写。
4,被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。
当描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便与阅读,而这个值不需要改变,所以加上final修饰。
作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。单词间通过_连接。
面向对象(抽象类)
当多个类中出现相同功能,但是功能主体不同,这时可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。这时方法加abstract(抽象),此时这个类也是抽象的,类也用abstract描述。例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
抽象类特点:
1,抽象方法一定在抽象类中。
2,抽象方法和抽象类都必须被abstract关键字修饰。
3,抽象类不可以用new创建对象。因为抽象方法没意义。
4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法,才能建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。要想子类不抽象,就必须复写父类所有的抽象方法。
抽象类和一般类没有太大不同。该如何描述事物就如何描述事物,只不过该事物出现了一些看不懂的东西。这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。通过抽象方法来表示。抽象类比一般类多了抽象方法,就是在类中可以定义抽象方法。抽象类不可以实例化。
特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
面向对象(模版方法设计模式)
需求:获取一段程序运行的时间。
原理:获取程序开始和结束的时间并相减即可。
获取时间:System.currentTimeMillis();
当代码完成优化后,就可以解决这类问题。
这种方式,模版方法设计模式。
什么是模版方法呢?在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去。由该类的子类去完成。
面向方法(接口)
接口:初期理解,可以认为是一个特殊的抽象类 当抽象中的方法都是抽象的,那么该类可以通过接口的形式来表示。
class用于定义类,interface用于定义接口(imeplements用于接口实现可以实现多实现,extends用于接口继承可以实现多继承。)
接口定义时,格式特点:
1,接口中常见定义:常量,抽象方法。
2,接口中的成员都有固定修饰符。
常量固定修饰符:public static final int NUM=3;
方法固定修饰符:public abstract void show();
记住:接口中的成员都是public的。
接口是不可以创建对象的, 因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全部覆盖后,子类才可以实例化。否则子类是一个抽象类。
接口可以被类多现实,也是对多继承不支持的转换形式。Java支持多实现。
一个类在继承一个类的同时,还可以实现多个接口。
接口与接口之间是继承关系。类与类之间是继承关系。类与接口之间是实现关系。extends关键词必须位于implements关键词之前。
接口与接口之间可以支持多继承。
接口特点:
1,对外暴露规则。
2,提高了功能的扩展性。
3,降低了耦合性。
接口实例:
基本功能定义在类中,扩展功能定义在接口中。
面向对象(多态-概念)
多态:可以理解为事物存在的多种体现形态。
人:男人,女人。
动物:猫,狗。
猫 x=new 猫();
动物 x=new 猫();
围绕以下4点学习。
1,多态的体现
父类或者接口的引用指向或者接收自己的子类对象。
2,多态的前提
必须是类与类之间有关系,要么继承,要么实现。
通常还有一个前提:就是存在覆盖。
3,多态的好处
多态的出现大大提高了程序的扩展性和后期可维护性。
4,多态的弊端:
虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员。
5,多态的应用
6,多态的出现代码中的特点(多态使用的注意事项)
在多态中成员函数(指非静态,因为非静态有重写特性)的特点:
在编译时间:对象所属类参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
在多态中成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类(父类))
在多态中静态成员函数的特点:无论编译和运行,都参考左边。
面向对象(多态-转型)
如果想调用子类(非父类成员)特用方法(成员)是怎么调用?
强制将父类的引用,转成子类类型。向下转型。
Animal a=new Cat();//类型提升。向上转型。
Cat c=(cat)a; 类型提升后又被强制转换。
我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
多态自始至终都是子类对象在做着变化。
Animal a=new Animal();
Cat c=(cat)a;这样操作是错的,千万不要出现这样的操作,就是将父类对象转成子类类型。
判断是否属于这一类用instanceof
if(a instanceof Cat)
{
Cat c=(Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog c=(Dog)a;
c.kanjia();
}
面向对象
Object:是所有对象的直接后者间接父亲,传说中的上帝。
该类中定义的肯定是所有对象都具备的功能。每个类都被extends Object;
Object类中已经提供了对对象是否相同的比较方法。
如果自定义类中也有比较相同的功能,没有必要重新定义。
只要沿袭父类中的功能,建立自己特有的比较内容即可。这就是覆盖。
面向对象(内部类访问规则)
1,内部类可以直接访问外部类成员,包括私有。之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式: 外部类名.this
2,要访问内部类,必须建立内部类对象。
访问格式:
1,当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中直接建立内部类对象。格式:外部类名.内部类 =外部类对象.内部类对象;
Outer.Inner in=new Outer().new Inner();
2,当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private:将内部类在外部类中进行封装。
Static:内部类就具备了静态的特性。
当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。
在外部其他类中,如何直接访问static内部类的非静态成员呢?
new Outer.Inner().function();
在外部其他类中,如何直接访问static内部类的静态成员呢?
Outer.Inter.function();
若想在成员内部类中访问外部类的成员变量,语法为:OuterClass.this.a;
注意:当内部类中定义了静态成员,该内部类必须是static的。
凡是被static修饰过的类,方法,变量等,她们都是随着类的加载而加载,都存放在内存中的方法区里,优先于对象建立,而非静态的东西要末存放在堆内存里(对象等),要末存放在栈内存里(变量等),他们不在同一块内存上。
类内部定义的静态成员,必须没有实例化就可以载入。
而内部类在没有静态修饰时,不能直接被外部类载入,其静态方法随之也不能载入。
只有新建一个内部类才能载入其成员,不符合静态的定义,所以会报错。
如果内部类定义了静态成员,则内部类必须是static的。原因同上,当静态成员随着类加载而加载时,若内部类不是static的,这时静态成员已经加载到内存上了,而内部类还没有建立,静态成员怎么能独立于他所属的内部类而存在呢?
静态 就是 没有实例化 就可以直接用类名去 引用的 成员。如果这个内部类不是静态的,你在这个类里面定义了静态的变量,连这个内部类都不能直接用外部类名去引用,
那你在里面定义内部变量就没有意义了。
一句话,内部类都是不确定的,怎么能确定内部静态的东西呢?内部类随着外部对象的建立,都会新产生一个内部类,所以内部类在哪里产生都不确定的,而且产生之后如果能调用静态方法,那么就会在方法区载入很多相同的静态方法,这样就与静态方法矛盾。
当外部类中的静态方法访问内部类时,内部类也必须是static的。
静态方法只能访问用static修饰的成员。
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
因为内部事务在使用外部事物的内容。
局部内部类不能定义静态成员,因为局部内部类不能被static修饰。
因为static只能修饰类中的成员,局部内部类跟局部变量一样,生命周期只存在于局部(即方法的大括号之间),方法执行完就消失,因此不需要修饰符修饰。(如果静态修饰也没用,因为生命周期很短,大括号外面就结束了。)
内部类定义在局部时:
1,不可以被成员修饰符修饰(final可以)
内部类定义在局部时,与局部变量的使用有些类似,局部变量只能被final修饰,而其他的成员修饰符是不能修饰局部变量的。这跟代码的生命周期有关系,局部变量的生命周期是从定义开始到最后一次被调用,而成员变量的生命周期比局部变量的周期长,因此用来修饰成员变量的修饰符不可以修饰局部变量。同样的道理,相对于定义在函数外时,内部类定义在内部时,其生命周期比较短,因此也不能被成员修饰符修饰。
2,可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。
因为方法中的代码是由上而下顺序执行的,方法运行结束后,局部变量就被销毁,内部类的生命周期可能会比局部变量的生命周期长;看下面的代码,方法中的内部类 Inner.class 调用方法中的局部变量 x ,正常调用的时候内部类能够调用到方法中的局部变量,并将内部类对象 inner 返回,正常调用结束后,如果方法中的局部变量 x 没有被 final 关键字修饰,x 则会被销毁,我们再通过反射的方式去调用 x 的时候则会发现找不到变量 x ,如果局部变量 x 被 final 关键字修饰后,则 x 在方法运行结束后不会被销毁,而是常驻在内存中直到 JVM 退出,这样再通过反射调用的时候依然可以找到 x 。
匿名内部类(没有名字的内部类):
1,匿名内部类其实就是内部类的简写格式。
2,定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口。
3,匿名内部类的格式:new 父亲或接口名称(){定义子类的内容}.fuction()或者父亲或接口名称 新建对象名=new 父亲或接口名称(){定义子类的内容}
4,其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。可以理解为带内容的对象。
5,匿名内部类中定义的方法最好不要超过3个(2个或一个比较好)。
匿名内部类是把建立子类和建立对象封装为一体的表现形式。所以匿名对象方法只能调用一次。
匿名对象一般不写子类特有的成员且不能强转类型。
什么时候用匿名类?
当接口中的方法只有1个或2个时,可以用。
没有父类也没有接口能使用匿名类吗?
用上帝之类。Object(所有类的父类)
异常
异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中的一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。(把问题封装成对象)
其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分,有2种;一种是严重的问题,一种是非严重的问题。
对于严重的:java通过Error类进行描述。
对于error一般不编写针对性的代码对其经行处理。
对于非严重的,java通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都具有一些共性内容。(所以可以向上抽取,共有父类Throwable)
比如:不正常情况的信息,引发原因等。
Throwable(Throwable类是java语言中所有错误或异常的超类。)
|——Error
|——Exception
异常的处理
Java 提供了特有的语句进行处理。
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
Finally
{
一定会执行的语句;
}
对捕获到的异常对象进行常见方法操作
对象.getMessage() :获取异常信息,返回对象的详细信息字符串。//异常信息
对象.toString()返回对象的简短描述//异常名称
对象.printStackTrace();//异常名称,异常信息,异常出现的位置。其实jvm默认的异常处理机制,就是在调用printStackTrace();方法。打印异常的堆栈的跟踪信息。
throws Exception//在功能上通过throws的关键字声明了该功能有可能会出现问题。(抛出可能出现的问题)
对多异常的处理。
1,声明异常时,建议声明更为具体的异常,这样处理的可以更具体。(声明多个具体异常就处理多个具体异常)
throws ArithmeticException,ArrayIndexOutofBoundsException声明了2个具体异常(抛出2个异常,可能出现问题的异常。)只要有异常发生,这个程序就已经结束了。(就是要被跳转)
2,对方声明几个异常,就对应有几个catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建议在进行catch处理时,catch中一定要定义具体处理方式。
不要简单定义一句e.printStackTrace(),
也不要简单的就书写一条输出语句。
一般是把这些异常用文字记录下来(bug),做为每天出现异常记录下来,然后进行修改。
自定义异常:
因为项目中会出现特有的问题。
而这些问题并未被java所描述并封装对象。
所以对于这些特有的问题可以按照java的对问题封装的思想。
将特有的问题。进行自定义的异常封装。
自定义异常。
需求:在本程序中,对于除数是负数,也视为是错误的,是无法进行运算的,那么就需要对这个问题进行自定义的描述。
throw new FushuException();//手动通过throw(与throws的区别,throws抛类,throw抛对象)关键字抛出一个自定义异常对象。
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
要么在内部try catch处理。
要么在函数上声明让调用者处理。
一般情况,在函数内出现异常,函数上需要声明。
发现打印的结果中只有异常的名称,却没有异常的信息。
因为自定义的异常并未定义所属信息。
如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了。
所以子类只要在构造时,将异常信息传递给父类通过super语句。
那么就可以直接通过getMessage方法获取自定义的异常信息。
自定义异常:
必须是自定义类继承Exception。
为什么要继承Exception?
异常体系有有一个特点:因为异常类和异常对象都被抛出。
他们都具备可抛性。这个可抛性是Throwable这个体系中的独有特点。
只有这个体系中的类和对象才可以被throws和throw操作。
Throws和throw的区别
1,throws使用在函数上(写在小括号和大括号之间),throw使用在函数内。
2,throws后面跟的异常类。可以跟多个。用逗号隔开。throw后面跟着是异常对象。
RuntimeException:
Exception中有一个非常特殊的子类异常RuntimeException运行时异常。
如果在函数内抛出抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过。
之所以不用在函数声明,是因为不需要让调用者处理。当该异常发生时,希望程序终止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,程序员对代码进行修正。
自定义异常时:如果该异常的发生,无法在继续进行运算,
就让自定义异常继承RuntimeException。
对于异常分两种:
1,编译时被检测的异常。(可以处理,继承Excepttion)
2,编译时不被检测的异常(运行时异常。RuntimeException以及其子类,不能处理直接结束,继承RuntimeException)
老师用电脑上课。这句话怎么用类描述?用名词提炼法
开始思考上课中出现的问题。
比如问题是
电脑蓝屏。
电脑冒烟。
要对问题进行描述,封装成对象。
可是当冒烟发生后,出现讲课进度无法继续。
出现了讲师的问题:课时计划无法完成。
finally:
finally代码块:定义一定执行的代码块。
通常用于关闭资源。
举例
public void method()
{
连接数据库;
数据操作;//throw new SQLException();
关闭数据库;//该动作,无论数据库操作是否成功,一定要关闭资源。
}
try
{
连接数据库;
数据操作;//throw new SQLException();
}
catch(SQLException e)
{
}
finally
{
关闭数据库
}
try ,catch(),finally有三种格式。
第一个格式:(一个try可以对应多个catch)
try
{
}
catch()
{
}
第二个格式:
try
{
}
catch()
{
}
finally
{
}
第三个格式:
try
{
}
finally
{
}
注意:
1,finally中定义的通常是关闭资源代码。因为资源必须释放。
2,finally只有一种情况不会执行,就是当执行到System.exit(0);(这是退出jvm系统的意思。)
只要问题被解决问题可以不用声明(问题没有被解决就一定要被声明),比如
try
{
throw new Exception();
}
catch(Exception e)
{
}
记住一点:catch是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常。那么必须声明(异常如果声明,声明在函数上)。
异常在子父类覆盖中的体现:
1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常类的子类。
2,如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3,如果父类或接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。
联习:有一个圆形和长方形。都可以获取面积。对于面积如果出现非法的数值,视为是获取面积出现问题。问题通过异常来表示。
先对这个程序进行基本的设计。
异常总结:
异常是什么?是对问题的描述。将问题进行对象的封装。
异常体系:
Throwable
|--Error
|--Exception
|--RuntimeException
异常体系的特点:异常体系中的所有类以及建立的对象都具备可抛性。
也就是说可以被throw和throws关键字所操作。
只有异常体系具备这个特点。
throw和throws的用法:
throw定义在函数内,用于抛出异常对象。
throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。
当函数内容有throw抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译失败。(注意:RuntimeException除外,也就是说,函数内如果抛出的是RuntimeException异常,函数上可以不用声明。)
如果函数声明了异常,调用者需要进行处理,处理方法可以是throws,也可以是try.
异常有两种:
编译时被检测异常
该异常在编译时,如果没有处理(没有抛也没有try),编译失败。
该异常被标识,代表这可以被处理。
运行时异常(编译时不检测)
在编译时,不需要处理,编译器不检查。
该异常的发生,建议不处理,让程序停止。需要对代码进行修正。
自定义异常:
定义类继承Exception或者RuntimeException
1,为了让该自定义类具备可抛性。
2,让该类具备操作异常的共性方法。
当要定义自定义异常的信息时,可以使用父类已经定义好的功能。
将异常信息传递给父类的构造函数。比如
class MyException extends Exception
{
MyException(String message)
{
super(message);
}
}
自定义异常:是按照java的面向对象思想,将程序中出现的特有问题进行封装。
异常的好处:
1,将问题进行封装。
2,将正常流程代码和问题相分离,方便与阅读。
异常的处理原则:
1,处理方式有两种:try或者throws。
2,调用到抛出异常的功能时,抛出几个,就处理几个。
一个try对应多个catch。
3,多个catch,父类的catch放到最下面。
4,catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,输出语句。 也不要什么都不写。
当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
try
{
throw new AException();
}
catch(AException e)
{
throw e;
}
如果该异常处理不了,但并不属于该功能出现的异常。
可以将异常转换后,在抛出和该功能相关的异常。
或者异常可以处理,但需要将异常产生的和本功能相关的问题提供出去,
让调用者知道。并处理。也可以将捕获异常处理后,转换新的异常。
try
{
throw new AException();
}
catch(AException e)
{
//对AException处理。
throw new BException();
}
比如汇款的例子。
异常的注意事项:
在子父类覆盖时:
1,子类抛出的异常必须是父类的异常的子类或者子集。
2,如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。
参阅
ExceptionText.java 老师用电脑上课
ExceptionText1.java 图形面积。
记住:throw单独存在时,下面不要定义语句,因为执行不到。(continue,return,break也是)
包package:
package 必须放在程序的第一行。
一个包中的类要被访问,必须要有足够大的权限。所以被访问的类必须要被public修饰。
类中的成员要被包外访问,也要公有才可以被访问。
总结:包与包之间进行访问,被访问的包中的类以及类中的成员,需要被public修饰才能被访问。
包与包直接的继承,有一个权限访问的好处,就是不同包的子类还可以直接访问父类中被protected权限修饰的成员。
包与包之间可以使用的权限只有两种,public protected。
public protected default private
同一个类中 ok ok ok ok
同一个包中 ok ok ok
子类 ok ok
不同包中 ok
类加public后,类名必须和java文件保持一致。所以同一个文件,只能一个类被public修饰。
import:为了简化类名的书写,使用的关键字,导入的是包中的类。不能导入子包中的类。
c:\myclass\packb\DemoA.class
c:\myclass\packb\haha\Demoz.class
import packb.*;导入DemoA
import pack.haha.*;导入Demoz(不建议用*,用哪个导哪个)
导入不同类时,如果类重名,必须加包名。
建议建立包名不要重复,可以使用url来完成定义,url是唯一的。
package cn.itcast.test(域名不会重复)
jar包(java的压缩包)
jar -cf haha.jar packa pack