6.0面向对象
6.1面向对象概念
6.1.1;理解面向对象
1. 面向对象是相对面向过程而言
2. 面向对象和面向过程都是一种思想
3. 面向过程
a) 强调的是功能行为
4. 面向对象
a) 将功能行为封装成对象,强调具备了功能的对象
5. 面向对象是基于面向过程的。
6.1.2面向对象的特点
1. 是一种符合人们思考习惯的思想
2. 可以将复杂的事情简单化
3. 将程序员从执行者转换成了指挥者
4. 完成需求时:
a) 先要去找具有所需的功能的对象来用
b) 如果该对象不存在,那么创建一个具有所需功能的对象
c) 这样简化开发并提高复用
6.1.3面向对象开发,设计,特征
1、 开发的过程:其时就是不断的找对象,建对象,用对象,指挥对象做事情
2、 设计的过程:其时就是在管理和维护对象之间的关系
3、 面向对象的特征:
a) 封装(encapsulation)
b) 继承(inheritance)
c) 多态(polymorphism)
6.2类与对象的关系
1、 使用计算机语言就是不断的在描述现实生活中的事物
2、 java中描述事物通过类的形式体现,类是具有事物的抽象,概念上的定义
3、 对象即是该类事物实实在在存在的个体
6.2.1类与对象(图例)
1、 类与对象的关系如图
2、 可以理解为:
a) 类就是图纸
b) 汽车就是堆内存中的对象
6.2.2类的定义
1、 生活中描述事物无非就是描述事物的属性和行为
1. 如:人有身高,体重等属性,有说话,打球等行为
2、 java中用类class来描述事物也是如此
1. 属性:对应类中的成员变量
2. 行为:对应类中的成员函数
3、 定义类就是在定义类中的成员(成员变量和成员函数)
6.2.3成员变量和局部变量的区别
1、 成员变量
1. 成员变量定义在类中,在整个类中都可以被访问
2. 成员变量随着对象的建立而建立,存在于对象所在的堆内存中
3. 成员变量有默认初始化值
2、 局部变量
1. 局部变量只定义在局部范围内,如:函数内,语句内等
2. 局部变量存在于栈内存中
3. 作用的范围结束,变量空间会自动释放
4. 局部变量没有默认的初始化值
6.2.4创建对象,使用对象
class Car//对Car这类事物进行描述
{
String color =“read”;
int num = 4;
void show()
{
System.out.println(“color=”+color+”..num=”+num);
}
}
class CarDemo
{
public static void main(String[] args)
{
Car c = new Car();//建立对象c为类类型对象,指向对象
c.color = “black”;//对对象的属性进行修改
c.show();//使用对象的功能
也可以在本类中创建本类对象,本类中由主函数,一般不写
6.2.5对象内存结构
Carc1 = new Car();c1.color=”blue”;
Carc2 = new Car();
6.2.6匿名对象
1、 匿名对象是对象的简化形式
a) Car c = new Car(); c.num = 5;可以用匿名对象简写
b) new Carr().num = 5;匿名对象简写格式
2、 匿名对象两种使用情况
a) 当对对象方法仅进行一次调用的时候,比较简化,不能进行多个调用。
b) 匿名对象可以作为实际参数进行传递
3、 匿名对象调用属性是没有意义的,调用方法是有一次意义
4、 匿名对象的栈内存及堆内存展示图:
6.3封装(Encapsulation)
1、 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式(有些说法是透明的)
2、 好处:
a) 将变化隔离
b) 便于使用
c) 提高重用性
d) 提高安全性
3、 封装原则:
a) 将不需要对外提供的内容都隐藏起来
b) 把属性都隐藏,提供公共方法对其访问
4、 函数是java代码中最小的封装体
6.4构造函数
1、 写法特点(格式固定)
a) 函数名与类名相同
b) 不用定义返回值类型(void是一种具体的返回值类型,表示没有返回值类型,而此处是不用定义返回值类型)
c) 不可以写return语句(因为此函数没有返回值类型,其他的函数不写系统会自动加上,而此处系统不加)
2、 作用
给对象进行初始化(对象一建立就会调用与之对应的构造函数)(当对象在堆内存中创建的时候,它需要一个初始化的动作)
3、 注意
a) 当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数,方便该类进行初始化,否则对象是建立不出来的。因为没有办法初始化。
b) 当在类中自定义了构造函数后,默认的构造函数就没有了。
c) 多个构造函数是以重载的形式存在的
4、 构造函数和一般函数的不同之处
a) 在写法上有不同(如上)
b) 在运行上也有不同。
i. 构造函数是在对象建立后就运行。给对象初始化。
ii. 一般方法是对象调用才执行,给对象添加对象具备的功能。
iii. 一个对象建立,构造函数只运行一次。
iv. 一般方法可以被该对象调用多次。
5、 定义构造函数的情况
a) 分析事物时,该事物一旦存在就具备一些特性或者行为,那么将这些内容定义在构造函数中。(一旦初始化就具有形参的可以带形参)
6、 构造代码块(面试笔试题)
a) 作用:给对象进行初始化。
b) 运行时间:对象一旦建立就运行,而且优先于构造函数执行。
c) 构造代码块和构造函数的区别:
i. 构造代码块是给所有对象进行统一初始化,
ii. 构造函数是给对应的对象初始化。
d) 构造代码快中定义的是不同对象共性的初始化内容。
e) 构造代码快格式:{执行语句;}
7、 构造函数可以被私有化(因为私有化是来修饰成员的,构造函数也是成员),私有化之后不可以创建对象,
8、 代码示例:
class Person
{
privateString name;
privateint age;
{ //构造代码块,优先于构造函数执行
System.out.println("person code run");
cry();
}
Person()//无参数构造函数
{
System.out.println("A: name="+name+",,age="+age);
}
Person(String n) //有name参数构造函数
{
name= n;
System.out.println("B:name="+name+",,age="+age);
//cry();
}
public void setName(String n)//设置name参数的函数
{
name = n;
}
public String getName()//获取name参数的函数
{
returnname;
}
Person(String n,int a) //有name,age参数构造函数
{
name= n;
age= a;
System.out.println("C:name="+name+",,age="+age);
//cry();
}
public void cry()//一般的函数
{
System.out.println("cry......");
}}
class PersonDemo2
{
publicstatic void main(String[] args)
{//四种不同的初始化方式,根据参数列表调用对应构造函数
Personp1 = new Person();
Personp2 = new Person("lisi");
p2.setName(“lili”);
System.out.println(p2.getName());//获取值打印
Personp3 = new Person("wnagu",10);
6.5this关键字
1、 特点
a) this代表其所在函数所属对象的引用(哪个对象在调用this所在的函数,this就代表哪个对象)
b) 换言之:this代表本类对象的引用(应用代码如下)
c) 加上this关键字,增强阅读性
2、 使用this关键字的情况
a) 当定义类中功能时,该函数内需要用到调用该函数的对象时,就用this表示这个对象。(this的应用代码如下)
b) 但凡本类功能内部使用了本类对象,都用this表示
c) 变量出现同名情况必须加this,否则可以省略
3、 类中的成员变量的使用都是对象进行调用的,本类中的对象用this表示
4、 this关键字的应用(看懂this代表对象的引用)
a) 需求:给人定义一个用于比较年龄是否相同的功能。也就是是否是同龄人
b) 主要代码:
public boolean compare(Person p)
{
return this.age==p.age;//相当于p1.age=p2.age;
}
}
class PersonDemo3
{
publicstatic void main(String[] args)
{
Personp1 = new Person(20);
Personp2 = new Person(25);
boolean b = p1.compare(p2);
System.out.println(b);
5、 示例代码:
class Person
{
privateint age;
Person(intage)
{
this.age = age;//这时的this就是p1
}
class PersonDemo3
{
publicstatic void main(String[] args)
{
Person p1 = new Person(20);
6、 构造函数间调用
a) 不能使用:函数名(参数);仅限于构造函数
b) 应使用:this(参数);称为this语句
c) 当私有化很多成员,对外公开很少量,这时就可以使用this语句进行构造函数间调用并初始化。
d) this语句只能定义在构造函数的第一行。因为初始化要先执行。(否则编译失败)
e) 一般函数不能调用构造函数,因为this语句不能用在一般函数中,只能用在构造函数间。(因为调用构造函数必须使用this语句)
f) 构造函数在初始化时,初始化的动作要先执行(且执行一次),如果初始化之中还有初始化,那就先执行那个更细节初始化,然后再执行自己的初始化
实例代码如下:(切记形成死循环,来回调用)
Person(String name)
{
this();//先执行
this.name=name;//后执行
}
Person(String name,int age)
{
this(name);//先执行
this.name= name;//后执行
this.age= age;
6.6static关键字
1、 static关键字
用于修饰成员(成员变量和成员函数)
2、 被修饰后的成员具备以下特点
a) 随着类的加载而加载:类被使用时要加载到内存时,静态的就已经存在了,在内存中开辟好了空间。随着类的消失而消失。说明他的生命周期最长。
b) 优先于对象存在
c) 被所有对象所共享
d) 除了可以被直接对象调用,也可以直接被类名调用
3、 使用注意事项
a) 静态方法只能访问静态成员(非静态方法既可以访问静态也可以访问非静态。)
b) 静态方法中不可以写this,super关键字(因为静态优先于对象存在。所以静态方法中不可以出现this。)
c) 主函数是静态的
d) 明确一点:静态变量先存在,对象后存在。
4、 静态变量有利有弊
a) 利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。可以直接被类名调用。
b) 弊端:生命周期过长。访问出现局限性。(静态虽好,只能访问静态。)
5、 静态使用的情况
a) 什么时候定义静态变量(类变量)呢?
i. 当对象中出现共享数据(值)时,该数据被静态所修饰。
ii. 对象中的特有数据要定义成非静态存在于堆内存中。
b) 什么时候定义静态函数呢?
i. 当功能内部没有访问到非静态数据(对象的特有数据),
ii. 那么该功能可以定义成静态的。
6、 特有内容随着对象存储在堆内存中,静态共享存储在方法区
7、 方法区:(共享区、数据区):用来存储类中的方法区,共享区
8、 实例变量和类变量的区别:
a) 存放位置。
i. 类变量随着类的加载而存在于方法区中。
ii. 实例变量随着对象的建立而存在于堆内存中。
b) 生命周期:
i. 类变量生命周期最长,随着类的消失而消失。
ii. 实例变量生命周期随着对象的消失而消失。
9、 代码示例:
Stringname;//成员变量也称为实例变量。
//静态的成员变量也称为类变量,存在时没有对象
staticString country = "CN";
10、 静态的应用---工具类的制作
a) 每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。
b) 当编译一个java文件时,如果这个文件中使用到其他的类的时候,JVM会在classpath指定的目录下,若没有则会在当前路径下,查找使用的相应的类的class文件,若没有相应的类的class文件,则JVM会再次查找一下当前目录下有没有相应类的java文件,如果有则先编译其相应的类的java文件,然后再编译本身java文件
DOS命令行的使用方法:
setclasspath=.;D:\myclass(ArrayTool.class文件的地址)
javac ArrayToolDemo.java
java ArrayToolDemo
a) 工具类中通常定义的是静态方法,直接用类名调用其静态函数
b) 虽然可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作。但还是发现了问题:
i. 对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
ii. 操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
c) 发现问题后,这时就考虑,让程序更严谨,是不需要对象的。可以将ArrayTool中的方法都定义成static的。直接通过类名调用即可。将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。为了更为严谨,强制让该类不能建立对象。可以通过将空的构造函数私有化完成。
d) 代码示例如下:
private ArrayTool(){}//空参数构造函数,私有化可以避免类不能使用对象。
public static int getMax(int[] arr)//定义静态函数
//工具类内部被封装的函数,不可以被类外调用。
private staticvoid swap(int[] arr,int a,int b)
11、 使用javadoc制作帮助文档(API应用程序接口)
a) java的说明书通过文档注释来完成(注释格式为:/**… …*/)
b) 凡是public修饰符的功能,都用文档注释描述,都可以文档注释功能工具所提取
c) 若将某个类生成注释文档,那么这个类必须是public修饰符修饰的类
d) 文档注释是准备暴露在外的内容,是要被用户使用的。私有的是不被体现的,即使写了文档注释javadoc也不会提取,它会判断他们的权限。只有两种权限才会被提取:public和protected。生成的方法必须是全静态的。构造函数不加public修饰符时,也不会生成文档注释,只有加上public修饰符才可以生成构造函数。
e) 一个类中默认会有一个空参数的构造函数,是系统自动加上的。这个默认的构造函数的权限和所属类一致。默认构造函数的权限是随着类的变化而变化。空参数的构造函数不是默认的构造函数,如果代码中有空参数的构造函数那是由程序员自定义的无参构造函数,默认是看不见的
f) 文档注释中的标识符说明(高级编辑工具是可以自动生成的,也有文档注释可以查询,其标识符)
i. “@”是能被文档注释功能工具所识别的一个字符
ii. “author”是作者的说明
iii. “version”是版本号的说明
iv. “param”是参数的说明
v. “return”是功能运行完后返回的一个结果
g) 格式说明:
/**
类的说明
@author 作者
@version V1.1
*/
h) 生成的帮助文档是以网页的形式体现的,要把这个网页存到哪里去,是个关键问题
i) 生成文档的格式
在DOS环境下运行
javadoc –d myhelp -author -version ArrayTool.java
i. 说明:
1. “javadoc”:文档注释提取工具
2. “-d”:建目录指令
3. “myhelp”:文档注释存放路径,只有名字表示当前路径;也可以指定绝对位置;没有此名字会自动创建一个目录(文件夹)。
4. “-author”、“-version”:选择性提取文档注释的相关信息:作者和版本
5. “ArrayTool.java”要编译的工具类文件
6.7主函数public static void main(String[] args)
main函数是一个特殊的函数。作为程序的入口,可以被JVM调用。
1、 主函数的定义:
a) public:代表着该函数访问权限是最大的。
b) static:代表主函数随着类的加载就已经存在了。
c) void:主函数没有具体的返回值。
d) main:不是关键字,但它是一个特殊的单词,可以被JVM识别。
e) (String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串。其中args是arguments的简写,只有此处可以变更。(约定俗称的习惯)
2、 主函数格式是固定的:JVM识别
3、 JVM在调用主函数时,传入的是new String[0];
4、 示例代码:主函数1调用主函数2,JVM执行主函数1
class MainDemo
{//主函数1调用主函数2,JVM执行主函数1
publicstatic void main(String[] args)//new String[]
{
String[] arr ={"hah","hhe","heihei","xixi","hiahia"};
MainTest.main(arr);//类名调用静态方法
}
}
//String[] args = new String[3];
//String[] args = null;
class MainTest
{//打印主函数接收的参数
publicstatic void main(String[] args)
{
for(intx=0; x<args.length; x++)
System.out.println(args[x]);
}
5、 在DOS命令行编译之后运行时,传参数,并打印
a) 先编译javac MainDemo.java
b) 后运行传参java MainDemo haha hehe heihei
c) 运行结果:haha hehe heihei
d) 代码如下:
class MainDemo
{//主函数调用主函数
publicstatic void main(String[] args)//new String[]
{
//for(int x=0; x<args.length; x++)//打印数组值
// System.out.println(args[x]); }
}
6.8private(私有)关键字
1、 private关键字
a) 是一个权限修饰符(最小权限)
b) 用于修饰类中的成员(成员变量和成员函数)
c) 被私有化的成员只在本类中有效
2、 常用之一
a) 将成员变量私有化,对外提供对应的set(),get()方法对其进行访问。提高对数据访问的安全性
示例程序:
private int age;
//set()方法一般返回值为void,且带有形式参数
publicvoid setAge(int a)
{
if(a>0&& a<130)//判断年龄的合法性
{
age= a;
speak();
}
else
System.out.println("非法 age");
}
//get()方法只获取,没有参数,返回值类型与获取一致
public int getAge()
{
returnage;
}
3、 注意
a) 在外部访问该私有成员时,编译通不过
b) set()和get()方法是规范写法,不是必须遵守的规则。
c) 对象的私有属性,一般有两个方法及set()和get()方法,是必须写的。这时的属性才会被封装起来。
d) 强调一点:封装不是私有,私有仅仅是封装的一种表现形式
e) 只要权限不在你所访问的范围内,都是封装。
f) 之所以对外提供访问方式,就是因为可以再访问方式中加入逻辑判断等语句。对访问的数据进行操作,提高代码的健壮性。
g) 若类中有setXX()和getXX()方法则该类中必有私有属性XX。
h) set()和get()方法内存演示图
6.9静态代码块
1、 格式
static
{
静态代码块中的执行语句;
}
2、 特点:
a) 随着类的加载而执行,只执行一次,并且优先于主函数,并且只能访问静态变量
3、 作用
a) 用于给类进行初始化(相对少用,一般对象初始化)
4、 当类被赋予空指向是,类没有被加载,静态代码块不被执行。
5、 区别:分别初始化顺序为依次为如下:
a) 静态代码块:初始化类
i. 格式:static{执行语句;}
b) 构造代码块:初始化对象(可以访问类成员)
i. 格式:{执行语句}
c) 构造函数:给对应对象初始化(参数列表)
i. 格式:类名(参数列表){执行语句}
6.10对象的初始化过程
Person p = new Person("zhangsan",20);
该句话都做了什么事情?
1、 加载类文件:因为new用到了Person.class.所以会先找到Person.class文件并加载到堆内存中。
2、 static代码块:执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3、 开辟内存空间:在堆内存中开辟空间,分配内存地址。此时栈内存中就有p
4、 对象默认初始化:在堆内存中建立对象的特有属性。并进行默认初始化(null和0的默认值初始化)。
5、 显示成员初始化:对属性进行显示初始化(类成员变量初始值)。
6、 构造代码块:对对象进行构造代码块初始化。
7、 构造函数:对对象进行对应的构造函数初始化。
8、 赋值:将内存地址付给栈内存中的p变量。
总结:初始化的先后顺序就是:主函数所在类的一些初始化(static代码块)à类加载 àstatic代码块,类初始化à为对象开辟堆内存空间和栈内存空间à堆内存中建属性默认初始化à属性显示初始化à构造代码初始化à构造函数初始化à内存地址赋给p
对象调用成员过程
1、 Person p = new Person("zhangsan",20);
p.setName(“lisi”);
2、 这句话做了什么事情?图示:
6.11单例设计模式
1、 设计模式:解决某一类问题最行之有效的方法。
2、 java中23种通用设计模式:规律,思想,框架
3、 单例设计模式:解决一个类在内存中只存在一个对象的问题
4、 保证对象唯一的必须三步:
a) 为了避免其他程序过多建立该类对象。先禁止其他程序建立该类对象(构造函数私有化)
b) 还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。(创建本类对象并静态)
c) 为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。(提供一个公共访问方法,类名调用)
5、 对于事物该怎么描述,还怎么描述。
a) 当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
6、 单例设计模式一:这个是先初始化对象,称为饿汉式(开发时常用此饿汉式:安全、简单)
特点:Single类一进内存,就已经创建好了对象。
class Single
{
private Single(){}//构造函数私有化
private static Single s = newSingle();//创建本类对象
public static Single getInstance()
//提供一个方法访问本类对象
{
return s;
}
}
class SingleDemo
{
publicstatic void main(String[] args)
{
Singles1 = Single.getInstance();//类名访问方法
Singles2 = Single.getInstance();
s1.setNum(23);
System.out.println(s2.getNum());
a) 饿汉式内存图示:
7、 单例模式二:对象是方法被调用时,才初始化,也叫做对象的延时加载,称为懒汉式。(开发一般不用,多个调用时就出问题)(面试题)
特点:Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{//加锁限制其他的程序,可以解决多个程序的问题
if(s==null)
{
synchronized(Single.class)//设计线程知识
{
if(s==null)
s = new Single();
}
}
return s;
}
}
6.12继承的概述
6.12.1继承的概述
1、 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的那个类即可。
2、 多个类可以称为子类,单独这个类称为父类、超类或者基类
3、 子类可以直接访问父类中的非私有的属性和行为
4、 通过extends关键字让类与类之间产生继承关系
a) class SubDemo extends Demo{}
5、 继承的优点
a) 继承的出现提高了代码的复用性
b) 继承的出现让类与类之间产生了关系,提供了多态的前提。
6.12.2继承的特点
1、 java只支持单继承,不支持多继承
a) 一个类只能有一个父类,不可以有多个父类
b) 因为多继承易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同时,子类对象不知道运行哪一个。
c) 此功能java优化了C++的功能,C++支持多继承。但是java保留了这种机制,并用另一种体现形式来完成表示即多实现。
d) class SubDemo extends Demo{} //ok
e) class SubDemo extends Demo1,Demo2,…{}//error
2、 java支持多层继承(继承体系)
a) class A{}
b) class B extends A{}
c) class C extends B{}
3、 如何使用一个继承体系的功能?(查阅父类功能,创建子类对象使用功能)
a) 想要使用体系,先查阅体系中父类的描述,因为父类中定义的是该类体系中的共性功能。
b) 通过了解共性功能,就可以知道该体系的基本功能,那么这个体系已经基本可以使用了。
c) 那么在具体调用时,要创建其子类的对象,为什么呢?
i. 因为父类不能创建对象(如抽象类和接口)
ii. 创建子类对象,可以使用更多的功能,包括基本的也包括特有的。
4、 定义继承需要注意
a) 不要仅为了获取其他类中某个功能而去继承
b) 类与类之间要有所属(“is a”)关系,xx1是xx2的一种。
5、 类中成员继承的一些特点
a) 变量
i. 父类和子类有非私有的相同的变量时,子类访问本类中的变量用this,子类访问父类的同名变量,用super。(这种情况几乎很少见)
ii. 内存图示:
b) 函数
i. 当父类和子类具有相同的方法时,,子类方法复写父类的方法(见下面的函数的覆盖)
c) 构造函数
i. 在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认的第一行有一条隐式的语句super();
ii. super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认的第一行都是super();
iii. 为什么子类一定要访问父类中的构造函数
1. 因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先看父类是如何对这些数据进行初始化的。
2. 所以子类在对象初始化时,要先访问父类中的构造函数。
3. 如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
iv. 注意:super语句一定要定义在子类构造函数的第一行。
v. 子类中必有一个构造函数访问父类
vi. this()和super()语句必须有其一作为构造函数的第一行(因为必须先对象初始化)。
6.13子类的实例化过程
1、 子类中所有的构造函数默认都会访问父类中空参数的构造函数
2、 因为每一个构造函数的第一行都有一条默认的语句super();
3、 子类会具备父类中的数据,所以要先明确父类是如何对这些数据初始化的
4、 当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。
5、 父类中也有super()语句,因为Object是所有类的父类。
6.14类与类之间的关系
1、 继承关系
2、 聚集关系:”has a”
a) 聚合关系:(球员和球队的关系)
b) 组合关系:(练习更紧密,手是身体的一部分)
6.15super关键字
1、 super和this的用法相同
2、 this代表本类应用,super代表父类应用
3、 当子类中出现同名成员时,可以用super进行区分
4、 子类要调用父类的构造函数时,可以使用super语句。
6.16函数覆盖(Override)
1、 子类中出现与父类中一模一样的方法时,会出现覆盖操作,也称为重写或者复写
2、 父类中的私有方法不可以被覆盖
3、 在子类覆盖方法中使用被覆盖的方法可以通过super.函数名获取
4、 覆盖注意事项
a) 覆盖时,子类方法权限一定要大于等于父类方法权限,否则编译失败
b) 静态只能覆盖静态(一般使用很少)
5、 覆盖的应用
a) 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,即沿袭了父类的功能,又定义了子类特有的内容。
b) 程序功能的扩展
6.17final关键字
1、 final是一个修饰符
2、 final可以修饰类,方法,变量
3、 final修饰的类不可以被继承
4、 final修饰的方法不可以被覆盖
5、 final修饰的变量是一个常量。只能被赋值一次,可以修饰局部变量和成员变量
6、 当描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便于阅读,而这些值不需要改变,所以加上final修饰。作为常量的书写规范,所有字母都大写,多个单词用下划线连接。
例如:public static final double PI = 3.14;//全局常量
7、 内部类只能访问被final修饰的局部变量
8、 (继承打破了封装性,可以复写掉)
6.18抽象类
1、 抽象类的概述
a) 抽象定义
i. 抽象就是将多个事物中共性的,本质的内容抽取出来
ii. 例如:狼和狗共性是犬科,犬科就是抽象出来的概念
b) 抽象类
i. java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类
c) 抽象方法的由来
i. 多个对象都具有相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法
ii. 例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
d) 抽象类和一般类的不同。
i. 该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。通过抽象方法来表示。
ii. 抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。
iii. 抽象类不可以实例化。
2、 抽象类的特点
a) 抽象类和抽象方法必须用abstract关键字修饰
b) 抽象方法只有方法声明,没有方法体,定义在抽象类中。
i. 格式:修饰符 abstract 返回值类型 函数名(参数列表);
c) 抽象类不可以被实例化,也就是不可以用new创建对象。原因:
i. 抽象类是具体事物抽象出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗
ii. 而且抽象类即使创建了对象,调用抽象方法也没有意义
d) 抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类
e) 抽象方法一定在抽象类中
3、 抽象类举例代码讲解
a) 雇员示例
i. 需求:公司中程序员有姓名,工号,薪水,工作内容
ii. 项目经理除了有姓名,工号(字符串类型),薪水,还有奖金,工作内容
iii. 对给出需求进行数据建模
b) 示例代码:
class Employee
{
privateString name;
private String id;//员工编号
privatedouble pay;
Employee(String name,Stringid,double pay)//员工构造函数{
this.name= name;
this.id= id;
this.pay= pay;
}
public abstract void work();//抽象函数
}
class Manager extends Employee
{
privateint bonus;
Manager(Stringname,String id,double pay,int bonus)
{
super(name,id,pay);
this.bonus= bonus;
}
publicvoid work()//经理类重写抽象函数
{
System.out.println("managerwork");
}
}
class Pro extends Employee
{
Pro(Stringname,String id,double pay)
{
super(name,id,pay);
}
publicvoid work()//普通员工重写抽象函数
{
System.out.println("prowork");
}
}
4、 抽象类相关问题
a) 抽象类中是否有构造函数
i. 有,抽象类是一个父类,要给子类提供实例的初始化。
b) 抽象关键字abstract不可以和哪些关键字共存?
i. final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
ii. private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。而抽象方法出现的就是需要被复写。
iii. static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。可是抽象方法运行没意义。
c) 抽象类中可不可以没有抽象方法
i. 特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。(不多见,有)
6.19模板方法设计模式
d) 需求:获取一段程序运行的时间。
e) 原理:获取程序开始和结束的时间并相减即可。
f) 获取时间的代码:System.currentTimeMillis();//参见API
g) 当代码完成优化后,就可以解决这类问题。
h) 什么是模版方法呢?
i. 在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去。由该类的子类去完成。
ii. 好处:提高了代码的扩展性和复用性
i) 示例代码(红色代码区域):
abstract class GetTime//获取代码运行时间的抽象类
{
public final void getTime()//确定的方法
{
long start = System.currentTimeMillis();
runcode();//不确定的方法,暴露出去
long end = System.currentTimeMillis();
System.out.println("毫秒:"+(end-start));
}
public abstract void runcode();//暴露的形式
}
class SubTime extends GetTime
{
public void runcode()
{
for(intx=0; x<4000; x++)
{
System.out.print(x);
}
}
}
class TemplateDemo
{
publicstatic void main(String[] args)
{
//GetTimegt = new GetTime();
SubTimegt = new SubTime();
gt.getTime();
}
}
6.20接口
1、 初期理解,可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式表示
2、 格式
interface{ }
3、 接口中的成员修饰符是固定的,且成员都是public的
a) 成员常量:public static final(定义的变量名应当大写)
b) 成员函数:public abstract(这些修饰符都可以省略的,系统会自动加上,建议全写,增加阅读性)
c) 代码示例(调用常量)
Test t = new Test();
System.out.println(t.NUM);//对象调用
System.out.println(Test.NUM);//类名调用
System.out.println(Inter.NUM);//接口名调用
4、 接口的出现将“多继承”通过另一种形式体现出来,即“多实现”
a) 为什么不能实现多继承,因为父类中的方法有方法体,而接口中的方法没有方法体,可以有子类自由的实现。
b) 在实现多接口的格式是:class implements InterA,InterB多个实现之间用的是逗号隔开他们的接口名
c) 实现多功能的方法是一个类先继承后实现,
格式为:classTest extends Demo implements InterA,InterB
d) 接口与接口之间的继承关系:接口可以实现多继承(都没有方法体,但是注意同名方法的返回值类型应一致)
格式为代码示例:
interface A
{
voidmethodA();
}
interface B extends A
{
voidmethodB();
}
interface C extends B,A
{
voidmethodC();
}
class D implements C
{
publicvoid methodA(){}
publicvoid methodC(){}
publicvoid methodB(){}
}
5、 类与接口的关系是实现关键字为“类名 implements 接口名”
6、 接口的特点
a) 接口是对外暴露的规则
b) 接口是程序的功能扩展(降低耦合性,一对一的关联)
c) 接口可以用来多实现
d) 类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
e) 接口与接口之间可以有继承关系
f) 接口是不可以创建对象的,因为有抽象方法,需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类。
7、 继承类与实现接口的关系
a) 继承是某的一种(所属一种),实现对象的特有功能(像一个)
b) 在组织中有体系是基本功能(用类表示),但是有一点副业就是扩展的(用接口表示)。
6.21多态
1、 定义:某一类事物的多种存在关系
a) 例:动物中的猫,狗
b) 猫这个对象对应的类型是猫类型
猫 x =new 猫();
c) 同时猫也是动物的一种,也可以把猫称为动物
动物 y =new 猫();
i. 动物是猫和狗具体事物中抽取出来的父类型
2、 体现
a) 父类或者接口的引用指向或者接收自己的子类对象
b) 父类型引用指向了自己子类对象
3、 作用
多态的存在提高了程序的扩展性和后期可维护性
4、 前提
a) 需要存在类与类之间的继承或者实现关系
b) 要有覆盖操作
5、 好处
多态的出现大大提高程序的扩展性
6、 弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员
7、 多态中的特点(存在父类中有指向子类的对象)
a) 成员函数(非静态,有覆盖操作,动态绑定)
i. 编译时:要查看引用变量所属的类中是否有所调用的方法,如果有,编译成功,否则失败。
ii. 在运行时:要查看对象所属的类中是否有所调用的方法,如果有,则运行子类自己的,没有则运行父类的,否则运行失败。
成员函数在多态调用时,编译看左边(声明),运行看右边(实例化)
b) 成员变量(面试题)
父类和子类中都有相同的变量名时。
无论编译和运行,都参考左边(引用变量所属的类)
示例代码如下:
// Fuf = new Zi();
// System.out.println(f.num);//结果是父类
// Ziz = new Zi();
// System.out.println(z.num);//结果是子类
c) 在多态中,静态成员函数的特点(面试题)静态绑定
静态成员函数,无论编译和运行,都参考左边
d) java继承在处理成员变量和成员方法时是有区别的。
i. 不管声明它们时用的什么类型,当它们这些变量调用方法时,方法的行为总是表现出它们实际类型的行为;
ii. 但是如果通过这些变量来访问它们所指对象的实例变量,这些实例变量的值总表现出声明这些变量所用类型的行为。
8、 多态的转型
a) 类型的转换
01、类型提升。 向上转型。
Animal a = new Cat();
a.eat();
02、强制将父类的引用转成子类类型。向下转型
Cat c = (Cat)a;
c.catchMouse();
03、注意:多态自始至终都是子类对象在作着变化
千万不要出现这样的操作,就是将父类对象转成子类类型。我们能转换的是父类引用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。以下不可以:
Animal a = new Animal();
Cat c = (Cat)a;
b) 引用类型判断的修饰符:instanceof用于判断对象的类型。
c) 格式:对象 intanceof 类型(类类型接口类型)
d) 应用范围:子类类型有限,(父类的判断语句不要写在前面),当用到此类型进行比较时,要对其类型进行判断一下,再进行比较。主要就是判断他的所属类型。
代码示例
if(a instanceof Cat)
{
Catc = (Cat)a;
c.catchMouse();
}
elseif(a instanceof Dog)
{
Dogc = (Dog)a;
c.kanJia();
}
9、 多态的应用
a) 将对象的调用变的简单,以前是指挥每一个对象做事情,现在是可以指挥一批对象做事情,那是因为找到了这些对象的共同所属类型。(将事物不停的向上抽象,你总能找到共同点,找到以后就可以统一操作很多对象)
b) 我们对类型进行抽取,导致了多态的产生,操作同一个大类型,对大类型中的所有小类型都能进行操作(多态的核心思想,就因为这个思想,才提高了多态的扩展性)
示例代码如下:
abstract class Student
{//抽取的第一步,都会学习和睡觉
publicabstract void study();
publicvoid sleep()
{
System.out.println("躺着睡");
}
}//抽取的第二步,调用,批量处理,建立对象,工具类
class DoStudent/
{
publicvoid doSome(Student stu)
{
stu.study();
stu.sleep();
}
}//基础班学员
class BaseStudent extends Student
{
publicvoid study()//复写父类方法之学习
{
System.out.println("basestudy");
}
publicvoid sleep()//复写父类方法之睡觉
{
System.out.println("坐着睡");
}
}//高级班学员
class AdvStudent extends Student
{
publicvoid study()//复写父类方法之学习
{
System.out.println("adv study");
}
}
class DuoTaiDemo3
{
publicstatic void main(String[] args)
{
DoStudentds = new DoStudent();
ds.doSome(newBaseStudent());
ds.doSome(newAdvStudent());
10、 多态的主板示例
需求:电脑运行实例,电脑运行基于主板
示例代码:
interface PCI//定义一个PCI接口,实现扩展
{
publicvoid open();
publicvoid close();
}//定义一个主板类
class MainBoard
{
publicvoid run()//主板运行方法
{
System.out.println("mainboardrun ");
}
//PCI p = new NetCard()//接口型引用指向自己的子类对象。
publicvoid usePCI(PCI p) //使用接口方法
{
if(p!=null)//判断加载的配件是否为空
{
p.open();
p.close();
}
}
}//定义一个网卡类实现了PCI接口
class NetCard implements PCI
{
publicvoid open()//网卡运行方法
{
System.out.println("netcardopen");
}
publicvoid close()//网卡关闭方法
{
System.out.println("netcardclose");
}
}//定义一个网声卡类实现了PCI接口
class SoundCard implements PCI
{
publicvoid open()//声卡打开方法
{
System.out.println("SoundCardopen");
}
publicvoid close()//声卡关闭方法
{
System.out.println("SoundCardclose");
}
}
class DuoTaiDemo5
{
publicstatic void main(String[] args)
{
MainBoardmb = new MainBoard();//主板对象
mb.run();
mb.usePCI(null);//PCI加载为空
mb.usePCI(newNetCard());//PCI加载网卡
mb.usePCI(newSoundCard());//PCI加载声卡
}
}
11、 多态的操作数据库示例
需求:数据库的操作(用户信息)
1,连接数据库。JDBC Hibernate
2,操作数据库。CRUD
c create r read u update d delete
3,关闭数据库连接。
代码示例:
interface UserInfoDao //定义操作数据的接口
{
publicvoid add(User user);
publicvoid delete(User user);
}//使用JDBC连接数据库,实现接口
class UserInfoByJDBC implementsUserInofDao
{
public void add(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
public void delete(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}//使用Hibernate连接数据库,实现接口
class UserInfoByHibernate implementsUserInfoDao
{
publicvoid add(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
publicvoid delete(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}
class DBOperate//操作数据
{
publicstatic void main(String[] args)
{
UserInfoByJDBC ui = newUserInfoByJDBC();
UserInfoByHibernate ui = newUserInfoByHibernate();
UserInfoDaoui = new UserInfoByHibernate();
ui.add(user);
ui.delete(user);
}
图示如下:
6.22object类
1、 Object:是所有对象的直接后者间接父类,传说中的上帝。
a) object类的equals()方法
i. 该类中定义的肯定是所有对象都具备的功能。
ii. Object类中已经提供了对对象是否相同的比较方法。
iii. 如果自定义类中也有比较相同的功能,没有必要重新定义。只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。(代码示例1)
iv. java认为所有的对象都具有比较性
b) object类的toString()方法
i. java认为所有对象都可以被认为是字符串而被打印
ii. 打印对象为字符串的结果是:对象的所属类和哈希值
代码示例:
Demo d1 = new Demo(5);//创建类demo的对象d1
Class c = d1.getClass();//类文件对象的定义
System.out.println(c.getName());//获取类文件的名字
System.out.println(c.getName()+"@@"+Integer.toHexString(d1.hashCode()));//字符串值的构成
System.out.println(d1.toString());//获取类文件的字符串值
代码示例1:
class Demo //extends Object
{
privateint num;
Demo(intnum)
{
this.num= num;
}
public boolean equals(Object obj)
//就相当于Object obj = new Demo();
{
if(!(objinstanceof Demo))//对对象的判断
returnfalse;
Demod = (Demo)obj;//对对象的向下强转
returnthis.num == d.num;
}
6.23内部类
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)
1、 访问特点
a) 内部类可以直接访问外部类中的成员,包括私有成员
之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this
b) 而外部类要访问内部类中的成员必须要建立内部类的对象
2、 内部类的位置
a) 内部类定义在成员位置上
i. 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中直接建立内部类对象。
格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
例如:Outer.Inner in = new Outer().new Inner();
ii. 当内部类在成员位置上,就可以被成员修饰符所修饰如被private成员修饰符修饰
iii. 当内部类被static修饰后只能访问外部类中的静态成员(出现的次数并不多)
在外部其他类中,如何直接访问static内部类的非静态成员呢?
格式:外部类对象.静态内部类非静态成员(对象)
例如:new Outer.Inner().function();
格式:外部类名.静态内部类名. 静态内部类静态成员(类名)
例如:Outer.Inner.function();
iv. 当内部类中定义了静态成员,该内部类必须是static的。
v. 当外部类中的静态方法访问内部类时,内部类也必须是static的。
b) 内部类定义在局部位置上
i. 局部变量不可被成员修饰符(private static)所修饰
ii. 内部类定义在局部位置上,也不可以定义其静态成员
内部类定义在局部位置上时调用方法
class Outer//定义的外部类
{int x=3;//外部类成员变量
void method()//外部类成员函数
void method(final int a)
//外部类成员函数接收的参数列表,必须是final
{ final int y = 4;//内部类所在的局部变量final修饰
class Inner//局部位置上的内部类
{
void function()//内部类的成员函数
{ //访问外部类的成员变量
System.out.println(Outer.this.x);
System.out.println(y);/访问所在的局部变量
}
}
//在外部类成员函数中创建内部类对象调用外部类成员变量
new Inner().function();
publicstatic void main(String[] args) //主函数
{
Outerout = new Outer();
out.method(7);//执行完之后,出栈操作,即便是final
out.method(8);//继续执行没有问题
iii. 可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。(代码示例如上)
c) 内部类在成员位置访问方式的代码示例
class Outer
{
privateint x = 3;// 访问方式=Outer.this.x
classInner//内部类
{
intx = 4;// 访问方式=this.x
voidfunction()
{
intx = 6;// 访问方式=x
System.out.println("innner:"+访问方式);
}
}
3、 内部类定义的原则
a) 当描述事物时,事物的内部还有事物,该事物用内部类来描述。
因为内部事务在使用外部事物的内容。
b) 人体访问心脏示例代码:(比较优良的设计模式)
class Body//外部人体
{
privateclass XinZang//内部心脏类
{ }
publicvoid show()//内部心脏类的访问方式
{//一般存在判断语句,才能允许访问
newXinZang(). //建立内部类对象访问内部类
}
}
4、 匿名内部类(编程AWT中经常使用,会写)
就是内部类的简化写法(目的:简化书写,覆盖方法)
a) 前提
内部类必须是继承一个类或实现一个接口
b) 格式
i. new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}
ii. “()”:构造函数
iii. “{ }”:类的大括号
c) 简单理解
i. 就是建立一个带内容的外部类或者接口的子类匿名对象
ii. 其实匿名内部类就是一个匿名子类对象
iii. 匿名内部类只能调用一次
d) 弊端
i. 不能直接调用自己的方法
ii. 不能进行强转动作
iii. 抽象方法过多不建议使用匿名内部类,匿名内部类中定义的方法最好不要超过3个,顶多两个或一个。
e) 匿名内部类的基本应用
i. 当使用的方法参数列表类型是接口类型时
ii. 经查看接口的方法,不超过3个
iii. 定义一个匿名内部类,把匿名内部类当参数传进去
代码示例:
黄色区域为参数列表,红色为匿名内部类
show(new Inter()
{
public void method()
{
System.out.println("method show run");
}
});//语法书写注意:大括号:子类区间;小括号:参数区间;分号:语句结束
public static void show(Inter in)//参数为接口,对象
{
in.method();
}
iv. 一个面试题
1. 以下程序的正误?
代码示例
class InnerTest
{
publicstatic void main(String[] args)
{//匿名内部类应用:类InnerTest的父类引用指向子类InnerTest子类的对象,必须匿名。
new Object()
{
public void function()
{ }
}.function();//调用子类对象的函数
}
}
v. 一个简单的思考
1. Test.function().method();//含义是什么?
a) Test.function():Test类中有一个静态的方法function。
b) .method():function这个方法运算后的结果是一个对象。而且是一个Inter类型(method()所属的类)的对象。
c) 因为只有是Inter类型的对象,才可以调用method方法。
匿名内部类代码示例
abstract class AbsDemo//定义的抽象类
{
abstractvoid show();//定义的抽象方法
}
class Outer//定义的外部类
{
intx = 3;
/* //定义的成员内部类,继承抽象类
class Inner extends AbsDemo
{
int num = 90;
void show() //复写抽象方法
{
System.out.println("show :"+num);
}
void abc() //内部类成员函数
{
System.out.println("hehe");
}
}
*/
public void function()//内部类成员函数
{
AbsDemo a = new Inner();//父类引用指向子类对象
Inner in = new Inner();//创建子类对象
in.show();//子类对象调用父类方法
in.abc();//子类对象调用子类方法
//创建AbsDemo的匿名子类对象,并为对象起一个名字叫AbsDemo d,此种方式的书写可代替上面内部类(红色字体)
AbsDemo d = newAbsDemo()//父类引用指向子类对象
{
int num = 9;
void show()
{
System.out.println("num==="+num);
}
void abc()
{
System.out.println("haha");
}
}.show();
d.show();//子类匿名对象调用父类方法,此语句也可以写在上面,如黄色区域
//d.abc();//编译失败,因为父类没有此方法,只有子类有,只有子类对象擦可以调用。
}
}
6.24异常
1、 异常:就是程序在运行时出现不正常情况。
2、 异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。其实就是java对不正常情况进行描述后的对象体现。
3、 对于问题的划分:一种是严重的问题,一种非严重的问题。
a) 对于严重的,java通过Error类进行描述。 对于Error一般不编写针对性的代码对其进行处理。
b) 对与非严重的,java通过Exception类进行描述。对于Exception可以使用针对性的处理方式进行处理。
4、 无论Error或者Exception都具有一些共性内容。
比如:不正常情况的信息,引发原因等。
5、 异常的体系(看父类对象建立子类对象)
a) 命名上,父类名是子类名的后缀
b) Throwable(可抛的)(异常的父类)
i. Error
1. 通常出现重大问题如:运行的类不存在或者内存溢出等
2. 不编写针对代码对其处理
ii. Exception
1. 在运行时运行出现的一起情况,可以通过trycatch final捕获
6、 Exception和Error的子类名都是以父类名作为后缀
7、 Throwable中的方法
a) getMessage()
获取异常信息,返回字符串
b) toString()
获取异常类名和异常信息,返回字符串
c) printStackTrace()
i. 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值是void。
ii. 其实JVM默认的异常处理机制,就是在调用printStackTrace()方法。打印异常的堆栈的跟踪信息。(stack:堆栈,trace:跟踪)
d) printStackTrace(PrintStreams)
通常该方法将异常内容保存在日志文件中,以便查阅
8、 throws和throw的区别
a) throws用于标识函数暴露出的异常(函数上)
b) throw用于抛出异常对象(函数内)
c) throws和throw的区别
i. throws用在函数上(就是定义在参数列表的小括号和方法体的大括号之间),后面跟异常类名,可跟多个用逗号隔开
ii. throw用在函数内(就是在方法体中),后面跟异常对象
9、 异常的声明及基本处理方式
a) 在函数上声明异常。便于提高安全性,让调用程序进行处理。不处理编译失败。
b) 调用有可能出现异常的程序时,有两种处理方式
i. 将异常抛出,则该异常就会逐级的被抛出,最后抛给JVM按默认的处理机制进行处理。
ii. 将调用有异常的程序,加入try…catch代码块中捕获处理。
c) 在功能上通过throws的关键字声明了该功能有可能会出现问题示例代码如下
int div(int a,int b) throws Exception
{
returna/b;
}
d) 在主函数中抛出异常的示例代码
publicstatic void main(String[] args) throws Exception
10、 异常处理
try
{
需要检测的代码;
}
catch(异常类 变量)通常写为(Exception e)
{
异常处理代码;
}
finally
{
一定会执行的代码;通常用于关闭资源(数据库的关闭)
}
a) 异常处理流程图
finally代码块只有一种情况不会被执行,就是在之前执行了System.exit(0);
b) 异常处理的格式
第一种
try
{
}
catch ()
{
}
第二种格式://编译可以通过,问题在内部被解决了,外界不知道,所以编译通过。只要是检测异常,问题被解决 就不用声明,问题未被解决,就必须被声明问题。
i. 解决的标准就是有没有catch语句。
try
{
throw newException();
}
catch (Exception e)
{
}
finally
{
}
第三种格式:
try
{
}
finally
{//关闭资源
}
ii. 记住一点:catch是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常。那么必须声明。解决的标准就是有没有catch语句。
11、 自定义异常
a) 出现的缘由
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。所以对于这些特有的问题可以按照java的对问题封装的思想。将特有的问题。进行自定义的异常封装。
b) 需求:在本程序中,对于除数是-1,也视为是错误的是无法进行运算的。那么就需要对这个问题进行自定义的描述。
c) 当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
i. 要么在内部try catch处理。
ii. 要么在函数上声明让调用者处理。
d) 一般情况在,函数内出现异常,函数上需要声明。
e) 发现打印的结果中只有异常的名称,却没有异常的信息。
f) 因为自定义的异常并未定义信息。
g) 如何定义异常信息呢?
i. 因为父类中已经把异常信息的操作都完成了。所以子类只要在构造时,将异常信息传递给父类通过super语句。那么就可以直接通过getMessage()方法获取自定义的异常信息。
h) 自定义异常:必须是自定义类继承Exception。
i) 继承Exception原因:
i. 异常体系有一个特点:因为异常类和异常对象都被抛出。他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。只有这个体系中的类和对象才可以被throws和throw操作。
j) 自定义类继承Exception或者其子类
k) 通过构造函数定义异常信息
例如:
class DemoException extends Exception
{
DemoException(String message)
{//构造函数中初始化信息是通过使用父类的信息
super(message)
}
}
l) 通过throw将自定义异常抛出
12、 异常细节
a) Exceptoin中有一个特殊的子类异常RuntimeException 运行时异常。
i. 如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。之所以不用在函数声明,是因为不需要让调用者处理。
ii. 如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
b) 自定义异常时:如果该异常的发生,无法在继续进行运算,就让自定义异常继承RuntimeException。
c) 对于异常分两种:
i. 编译时被检测的异常。(处理后程序还能继续运行的异常)
ii. 编译时不被检测的异常(运行时异常。RuntimeException以及其子类)
d) 一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类
e) 如果父类抛出多个异常,那么重写(覆盖)方法必须抛出那些异常的一个子集,不能抛出新的异常
f) 异常在子父类覆盖中的体现;
i. 子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。或者不抛。
ii. 如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
iii. 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。
13、 对多异常的处理
a) 声明异常时,建议声明更为具体的异常。这样处理的更具体。
b) 函数只要有异常发生,不处理就会立即结束,不会出现存在两个异常的情况。
c) 对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。
d) 如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
e) 建立在进行catch处理时,catch中一定要定义具体处理方式。不要简单定义一句e.printStackTrace(),也不要简单的就书写一条输出语句。
i. 处理方式:将异常信息输出到硬盘,形成异常日志文件
14、 throw语句同return语句一样,是程序的结束语句,后面不能有语句。
6.25包(package)
1、 对类文件进行分类管理
2、 给类提供多层命名空间
3、 写在程序文件的第一行
4、 类名的全称是 包名.类名
5、 包也是一种封装形式
6、 包名所有字母小写,类名接口名首字母大写。
7、 好处是使得java的源文件和运行文件分离。
8、 在设置classpath时,只需要指定到包的父目录即可。
9、 类的权限修饰符只有public和没有修饰符的。
包之间的访问
1、 被访问的包中的类权限必须是public的
2、 类中的成员权限:public或者protected
3、 protected是为其他包中的子类提供的一种权限
6.26四种权限
![](https://img-my.csdn.net/uploads/201302/20/1361301441_7107.jpg)
6.27import
1、 简化类名
2、 一个程序文件中只有一个package,可以有多个import
3、 用来导包中的类,不导入包中的包
4、 通常写import mypack.Demo;而不写import mypack.*;
6.28Jar包
1、 java的压缩包
a) 方便项目的携带
b) 方便与使用,只有在classpath设置jar路径即可
c) 数据库驱动,SSH框架等都是以jar包体现的。
2、 jar包的操作
通过jar.exe工具对jar的操作
a) 创建jar包
jar -cvf mypack.jar packa packb
b) 查看jar包
jar -tvf mypack.jar [>定向文件]
c) 解压缩
jar -xvf mypack.jar
d) 自定义jar包的清单文件
jar -cvfm mypack.jar mf.txt packa packb