知识提纲
1,抽象
2,接口
3,多态
4,内部类(匿名)
5,异常
6,包
1、抽象
1.1、抽象的定义
抽象就是从多个事物中将共性的,本质的内容抽取出来。
例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。
1.2、抽象类
Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
抽象类的由来:
多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
1.3、抽象类的特点
1、抽象类和抽象方法必须用abstract关键字来修饰。
2、抽象方法只有方法声明,没有方法体,定义在抽象类中。
格式:修饰符abstract返回值类型 函数名(参数列表);
3、 抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:
抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。
而且抽象类即使创建了对象,调用抽象方法也没有意义。
4、抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。
/*
练习
员工类:name id pay
经理类:继承了员工类,并有自己特有的bonus
*/
class Employee
{
private String name;
private String id;
private double pay;
Employee(String name,String id,double pay)
{
this.name=name;
this.id=id;
this.pay=pay;
}
public abstract void work();
}
class pro extends Employee
{
pro (String name,String id,double pay)
{
super(name,id,pay);
}
public void work()
{
System.out.println("pro work");
}
}
class Manage extends Employee
{
private int bonus;
Manage(String name,String id,double pay,int bonus)
{
super(name,id,pay);
this.bonus=bonus;
}
public void work()
{
System.out.println("manage work");
}
}注:抽象类中可以有非抽象的方法。
抽象类和一般类没有太大不同
该怎样描述事物就怎样描述事物,只是,该事物出现一些看不懂的东西
这些不确定的部分,也是该事物的功能,需要明确出现,但是无法定义主体
通过抽象方法来表示
抽象类比一般类多了个抽象函数,就是在类中可以定义抽象方法。
抽象类不可以实例化
特殊:抽象类中可以不定义抽象方法,这杨做仅仅是不让该类建立对象
abstract class Student
{
abstract void study(); //抽象方法,能继承,不能实例化
}
class BaseStudent extends Student
{
void study()
{
System.out.println("base study");
}
}
class AdvStudent extends Student
{
void study()
{
System.out.println("adv study");
}
}
class AbstractDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
1.4、抽象类与一般类的区别
1、抽象类和一般类没有太大的不同。该如何描述事物,还是如何描述事物。只不过,该事物中出现了一些不知道具体内容的方法部分。这些不确定的部分,也是该事物的功能,需要明确出来,但是无法定义主体。通过抽象方法来表示。
2、抽象类比一般类多了个抽象函数。就是在类中可以定义抽象方法。
3、抽象类不可以实例化。
4、抽象类虽然不能创建对象,但是也有构造函数。供子类实例化调用。
注:1、被abstract修饰的函数不能同时被private、final、static修饰。
原因:
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private:抽象类中的私有的抽象方法,不被子类所知,就无法被复写。
而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
可是抽象方法运行没意义。
2、抽象有一个特殊的地方:抽象类中可以不定义抽象方法。这样做可以不让本来实例化,也可以用于模块设计。
/*
月饼的制作;;;思想最重要
需求:获取一段程序的运行时间
原理:获取程序开始和结束的时间并相减即可
获取时间: System.currentTimeMillis();
当代码完成优化后,就可以解决这类问题
这中方式叫做 模板方法设计模式
什么是模板方法呢?
就是在定义功能时,功能的一部分是确定的,但有一部分是不确定的,而确定的部分在使用不确定的部分,
那么这时将不确定的部分暴露出去,由该类的子类去完成
*/
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 (int i=0;i<4000 ;i++ )
{
System.out.print("i="+i);
}
}
}
class TemplateDemo
{
public static void main(String[] args)
{
//GetTime get=new GetTime();
SubTime sub=new SubTime();
sub.GetTime();
//get.getTime();
}
}
2、接口
2.1、概述:接口,可以被认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。接口使用interface来表示,子类中用implements实现。格式为:
interface 接口名{}
子类名 implements接口名{}
格式特点:
1、接口中常见定义:常量,抽象方法。
2、接口中的成员都有固定修饰符。
常量:public static final
方法:public abstract
3、接口中的成员都是public的。
在使用中,常量可以不写publicstatic final,方法可以不写publicabstract,编译时Java会自动添加这些修饰符,因为这是固定的格式修饰符。但为了方便阅读,通常我们都写上。
2.2、特点
1、接口是对外暴露的规则。
2、接口是程序的功能扩展。
3、接口的出现降低耦合性。
4、接口可以用来多实现。这也是对多继承不支持的转换形式。java支持多实现。
5、类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。
6、 接口与接口之间可以有继承关系。而且可以多继承。
注:1、接口不可以创建对象的,因为有抽象方法。需要被子类实现(implements),子类对接口中的抽象方法全都覆盖后,子类才可以实例化。否则子类是一个抽象类。
2、实现多个接口时,接口中不可以有返回不同类型的同名抽象函数。这样子类实现时将不能复写
2.3、接口与抽象类
共性:都是不断向上抽取出来的抽象的概念。
区别:
1、抽象类体现继承关系,一个类只能单继承。
接口体现实现关系,一个类可以多实现。同时接口与接口之间有继承关系。
2、抽象类是继承,是 "is a "关系。
接口是实现,是 "like a"关系。
3、抽象类中可以定义非抽象方法,供子类直接使用。
接口的方法都是抽象,接口中的成员都有固定修饰符。
4、抽象类中可以私有变量或方法。
接口中的常量和方法都是public修饰的权限。
/*
接口:初期理解,可以认为是一个特殊的抽象类
当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示
class用于定义类
interface 用于定义接口
接口定义时,格式特点:
1、接口中常见定义: 常量,抽象方法
2、接口中的成员都有固定修饰符
常量:public static final
方法:public abstract
总结:接口中的成员都是public 的
接口;是不可以创建对象的,因为有抽象方法
需要被子类实现,子类对接口中的抽象方法全部覆盖后,子类才可以实例化
否则子类是一个抽象类
接口可是被类多实现,也是对多继承不支持多转换形式,java支持多实现
java可以实现多继承,但是只在接口中实现
*/
interface Inter
{
//int NUM=3; //这样也可以,会自动添加
//void show();
public static final int NUM=3;
public abstract void show();
}
interface InterA
{
public abstract void method();
}
class Demo
{
public void function(){}
}
class Test extends Demo implements Inter,InterA //实现接口,类是继承,接口全是抽象,实现
{
public void show(){}
public void method(){}
}
interface A
{
void methodA();
}
interface B //extends A
{
void methodB();
}
interface C extends B,A
{
void methodC();
}
class C implements C
{
public void methodA(){}
public void methodB(){}
public void methodC(){}
}
class InterfaceDemo
{
public static void main(String[] args)
{
Test t=new Test();
System.out.println(t.NUM);
System.out.println(Test.NUM);
System.out.println(Inter.NUM);
}
}
3、多态
多态:可以理解为事物存在的多种体现形态
动物:猫,狗
猫 X=new 猫();
动物 x=new 猫();
3.1、多态的体现
父类的引用指向了自己的子类对象
父类的引用也可以接收自己的子类对象
3.2、多态的前提
必须是类与类之间有关系,要么继承,要么实现
还有一个前提,存在覆盖
3.3、多态的好处
多态的出现大大的提高了程序的扩展性
3.4、多态的弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员
3.5、多态的应用
3.6、多态的出现代码中的特点(多态使用的注意事项)
abstract class Animal
{
public abstract void Eat();
}
class Cat extends Animal
{
public void Eat()
{
System.out.println("Eat Fish!");
}
public void CatchMouse()
{
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
public void Eat()
{
System.out.println("吃骨头");
}
public void KanJia()
{
System.out.println("看家");
}
}
class Pig extends Animal
{
public void Eat()
{
System.out.println("饲料");
}
public void GongDi()
{
System.out.println("拱地");
}
}
class DuoTaiDemo2
{
public static void main(String[] args)
{
//Animal a=new Cat(); //类型提升 向上转型,
//a.Eat();
//如果想要调用猫的特有方法(抓老鼠)时,如何操作?
//强制将父类的引用,转成子类类型
//Cat c=(Cat)a; //向下转型
//c.CatchMouse();
//千万不要出现这杨的操作,就是将父类对象转成子类类型
//我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换
//多态至始至终都是子类对象在做着变化
//Animal a = new Animal();
//Cat c = (Cat)a;
Function(new Dog());
Function(new Cat());
}
public static void Function(Animal a) //Animal a=new Cat();
{
a.Eat();
if(a instanceof Cat)
{
Cat c =(Cat)a;
c.CatchMouse();
}
else if(a instanceof Dog)
{
Dog d=(Dog)a;
d.KanJia();
}
}
}
3.7、在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败
在运行时期:参阅对象所属的类是否有调用的方法
总结:成员函数在多态调用时,编译看左边,运行看右边
在多态中,成员变量的特点:
无论编译和运行,看左边
在多态中,静态成员函数的特点:
无论编译和运行,看左边
class Fu
{
int num=5;
void method1()
{
System.out.println("fu_method_1");
}
void method2()
{
System.out.println("fu_method_2");
}
static void method4()
{
System.out.println("fu_method_4");
}
}
class Zi extends Fu
{
int num=8;
void method1()
{
System.out.println("zi_method_1");
}
void method3()
{
System.out.println("zi_method_3");
}
static void method4()
{
System.out.println("zi_method_4");
}
}
class DuoTaiDemo4
{
public static void main(String[] args)
{
//Fu f=new Zi();
//System.out.println(f.num);
//Zi z=new Zi();
//System.out.println(z.num);
//f.method1();
//f.method2();
//f.method3();
Fu f=new Zi();
f.method4();
//Zi z=new Zi();
//z.method1();
//z.method2();
//z.method3();
}
}
3.8多态的应用
1、定义好工具类,即将共同行为封装在一个类中。
2、对类型进行抽取,---->多态的产生。
3、操作同一父类型,对其中的子类型均可操作
/*
需求:
电脑运行实例
电脑运行基于主板
*/
interface PCI
{
public void open();
public void close();
}
class MainBoard
{
public void run()
{
System.out.println("mainboard run");
}
public void usePCI(PCI p) //PCI p=new NetCard();
{
if(p!=null)
{
p.open();
p.close();
}
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("netcard run");
}
public void close()
{
System.out.println("netcard close");
}
}
class SoundCard implements PCI
{
public void open()
{
System.out.println("soundcard run");
}
public void close()
{
System.out.println("soundcard close");
}
}
/*
class MainBoard
{
public void run()
{
System.out.println("mainboard run");
}
public void useNetCard(NetCard c)
{
c.open();
c.close();
}
}
class NetCard
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
}
}
*/
class DuoTaiDemo5
{
public static void main(String[] args)
{
MainBoard mb=new MainBoard();
mb.run();
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}
4,内部类
4.1、概述
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
当描述事物时,事物的内部还有事物,该事物用内部类来描述。因为内部事物在使用外部事物的内容。如定义一个描述人的类,而手、心脏等都属于人,然它们又有自己的功能描述,这时可以在人这个描述类中,定义一个描述心脏的类,也就是内部类。
编译时,如果代码中有内部类,生成的class文件中会含有这样的文件:Test$1.class。编译器将会把内部类翻译成用$(美元符号)分隔外部类名和内部类名的常规类文件。这是内部类的一种编译现象。
/*
内部类的访问规则
1、内部类可以直接访问外部类中的成员,包括私有
之所以可以直接访问外部类中的成员,是因为内部类中持有一个外部类的引用,格式 外部类名.this
2、外部类要访问内部类,必须建立内部类对象
直接访问内部类,注意格式 Outer.Inner in=new Outer().new Inner();
当内部类在成员位子上,就可以被成员修饰符所修饰
比如: private static // private class Inner
注意静态类只能访问静态成员,当内部类被static修饰后,只能直接访问外部类中的static成员,出现访问局限
当外部其他类中,如何直接访问static内部类的非静态成员呢
new Outer.Inner().Function();
在外部其他类中,如何直接访问static内部类的静态成员呢?
Outer.Inner.Function();
注意:当内部类中定义了静态成员,该内部类必须是static的
当外部类中的静态方法访问内部类时,内部类也必须是static
类是描述事物, 当描述事物时,事物内部还有事物,该事物用内部类来描述
因为内部事物在使用外部事物的内容
class Body //内部类封装,不能直接访问,但提供了方法可以访问
{
private class heart
{
}
public void show()
{
new heart();
}
}
*/
class Outer //外部类
{
private int num=5;
static class Inner //内部类,内部类可以用private 修饰
{
//int num=10;
void Function()
{
// int num=15;
//num=15, this.num=10; outer.this.num=5;
System.out.println("inner class"+Outer.this.num);
}
}
class Inner2
{
void show()
{
System.out.println("inner2 class");
}
}
public void method()
{
Inner i=new Inner();
i.Function();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
//Outer o=new Outer();
//o.method();
//直接访问内部类,注意格式 Outer.Inner in=new Outer().new Inner();
Outer.Inner in=new Outer().new Inner();
in.Function();
// new Outer.Inner().Function();
}
}
4.2、匿名内部类
1、匿名内部类其实就是内部类的简写格式。
2、定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口。
特殊情况:因为所以的类都有一个父类Object,所以在定义时也可以用Object。
3、匿名内部类的格式: new父类或者接口(){定义子类的内容}
4、其实匿名内部类就是一个匿名子类对象。可以理解为带内容的对象。
5、匿名内部类中定义的方法最好不要超过3个。
匿名内部类的利与弊:
好处:简化书写
弊端:1、不能直接调用自己的特有方法、
2、不能做强转动作。
3、如果继承的父类或接口中有很多方法时,使用匿名内部类阅读性会非常差,且调用会很麻烦。所以匿名内部类中定义的方法有一般不超过3个。
interface Inter
{
void method();
}
class Test
{
//使用匿名内部类方法
/*
static class Inner implements Inter
{
public void method()
{
System.out.println("method run");
}
}*/
static Inter function()
{
return new Inter()
{
public void method()
{
System.out.println("method run");
}
};
}
}
class InnerClassTest
{
public static void main(String[] args)
{
//分析: Test.function():知道Test类中有一个静态的方法function();
//.method(); 到这一步可以知道function()方法运算后的结果是一个对象,而且是一个Inter类型的对象
//因为只有是Inter类型的对象,才可以调用method方法
Test.function().method();
//Inter in =Test.function();
//in.method();
}
}
5, 异常
5.1、概述
1、异常:就是程序在运行时出现不正常情况。
2、异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。其实就是java对不正常情况进行描述后的对象体现。
3、程序可能出现的错误或问题
a、用户输入错误导致的异常:如用户不正常使用程序,输入一些非法参数
b、设备硬件等发生的错误:如硬盘损坏等
c、物理限制:如存储空间不足等
d、代码错误:在程序编写的方法可能不正确,返回错误参数等。
5.2、异常体系
有两种对问题的划分方式:
一种是严重的问题;
一种是非严重的问题。
对于严重的问题,java通过Error类进行描述。对Error类一般不编写针对性的代码对其进行处理。
对于非严重的,java通过Exception类进行描述。对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都具有一些共性内容。比如:不正常情况的信息,引发原因等。
这也就构成了Java的异常体系:
Throwable
|---Error //通常出现重大问题如:运行的类不存在或者内存溢出等。
|---Exception //运行时出现的一起情况
|---R untimeException //特殊异常类,抛时不需要声明
Exception和Error的子类名都是以父类名作为后缀。
异常体系的特点:
1、异常体系中的所有类以及建立的对象都具备可抛性。
2、也就是说可以被throw和throws关键字所操作。
3、只有异常体系具备这个特点。
5.3、异常有两种:
1、编译时被检测异常
该异常在编译时,如果没有处理(没有抛也没有try),编译失败。该异常被标识,代表着可以被处理。
2、运行时异常(编译时不检测)
在编译时,不需要处理,编译器不检查。该异常的发生,建议不处理,让程序停止。需要对代码进行修正。如:RuntimeException以及其子类。
5.4、 异常的处理
1、 java提供了特有的语句进行处理。
try
{
需要被检测的代码。
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
有三个结合格式:
a、try
{
}
catch ()
{
}
b、try
{
}
finally
{
}
c、try
{
}
catch ()
{
}
finally
{
}
注意:
1)finally中定义的通常是关闭资源代码。因为资源必须释放。
2)如果在一个功能中,定义了一些必须要执行的代码,可以用try{}finally{}的方式,将一定执行的代码放在finally代码块中。
3)finally只有一种情况不会执行。当执行到System.exit(0);fianlly不会执行。
2、throw和throws的用法
throw定义在函数内,用于抛出异常对象。
throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。
当函数内容有throw抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译失败。
注意:RuntimeException除外。也就说,函数内如果抛出的RuntimeExcpetion异常,函数上可以不用声明。
3、调用者对抛出信息的处理
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try catch处理。要么在函数上声明让调用者处理。
一般情况下,函数内出现异常,函数上需要声明。在功能上通过throws的关键字声明了该功能有可能会出现异常类型。
特殊之处:
Exception中有一个特殊的子类异常RuntimeException运行时异常。
1) 如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。
2)如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过。
之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
如果函数声明了异常,调用者需要进行处理。处理方法可以throws可以try。
对捕获到的异常对象进行常见方法操作:
String getMessage();//获取异常的信息。返回字符串。
toString();//获取异常类名和异常信息,返回字符串。
printStackTrace();//获取异常类名和异常信息,以及异常出现在程序中的位置.返回值void.
//其实JVM默认的异常处理机制,就是在调用printStackTrace方法,打印异常的堆栈的跟踪信息。
printStackTrace(PrintStream s)//通常用该方法将异常内容保存在日志文件中,以便查阅。
5.5、自定义异常
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。所以对这些特有的问题可以按照java中的面向对象思想。将特有的问题,进行自定义的异常封装。定义类继承Exception或者RuntimeException
1,为了让该自定义类具备可抛性。
2,让该类具备操作异常的共性方法。
这就叫做自定义异常。
当自定义了异常类继承Exception后,如果未在类中定义异常信息,那么通过toString方法打印出来的结果就只有自定义的异常类名,不会显示异常信息。那么应该如何定义异常信息呢?
要定义自定义异常的信息时,可以使用父类已经定义好的功能。异常信息传递给父类的构造函数。因为父类中已经把异常信息的操作都完成了。所以子类只要在构造时,将异常信息传递给父类通过super语句。那么就可以直接通过getMessage方法获取自定义的异常信息。
自定义异常时:如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException。
注:自定义异常:
必须是自定义类有继承关系,通常继承Exception。
继承Exception原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。
只有这个体系中的类和对象才可以被throws和throw操作。
/*
项目中会出现特有的问题
对于一些特有的问题进行自定义的异常封装
自定义异常
需求:在a/b中,b不能等于零和小于零
当在函数内部出现throw抛出异常对象,那么就必须要给对应处理动作
1 用try catch 处理
2、在函数上声明让调用者处理
一般情况,函数内出现异常,函数上需要需要声明
定义异常信息
自定义异常必须继承Exception
原因:因为异常和异常对象都有可抛性
throws和throw的区别
throws使用在函数上
thro使用在函数内
throws后面根的是函数上
throw定义在函数内
*/
class FuShuException extends Exception
{
private String msg;
FuShuException(String msg)
{
this.msg=msg;
}
public String getMessage()
{
return msg;
}
}
class Demo
{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw new FuShuException("除数出现负数"); //手动通过throw抛出自定义异常
return a/b;
}
}
class ExceptionDemo3
{
public static void main(String[] args) //throws Exception
{
Demo d=new Demo();
try
{
int x=d.div(4,-1);
System.out.println("x=="+x);
}
catch (FuShuException e)
{
System.out.println("出现负数");
System.out.println(e.getMessage()); //by zero
System.out.println(e.toString());
e.printStackTrace(); //异常名称,异常信息,异常出现的位子
//其实jvm默认的异常处理机制,就是在调用printStackTrace方法
}
System.out.println("over");
}
}
5.6、异常的好处与原则
好处:
1、将问题进行封装。
2、将正常流程代码和问题处理代码相分离,方便于阅读。
原则:
1、处理方式有两种:try或者 throws。
2、调用到抛出异常的功能时,抛出几个,就处理几个。一个try对应多个catch。
3、多个catch时,父类的catch放到最下面。否则编译会报错,因为其余的catch语句执行不到。
4、catch内,需要定义针对性的处理方式。不要简单的定义printStackTrace,输出语句。也不要不写。当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
5.7、异常的注意事项
1、问题在内部被解决就不需要声明。
2、catch是用于处理异常。如果没有catch就代表异常没有被处理,如果该异常是检测时异常。那么必须声明。
3、在子父类覆盖时:
a,子类抛出的异常必须是父类的异常的子类或者子集。
b,如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。
/*
Exception中有一个特殊的子类异常RuntimeException 运行时异常
在函数内抛出该异常,函数上不用声明,编译通过
自定义异常时,如果该异常的发生,无法再继续进行运算
就让自定义异常继承 RuntimeException
对于异常分两种:
1、编译时被检测的异常
2、编译时不被检测的异常,(运行时异常,RuntimeException及其子类)
*/
class Demo
{
int div(int a,int b)throws Exception
{
if(b<0)
throw new Exception("被负数除了");
if(b==0)
throw new ArithmeticException("被零除了"); //手动通过throw抛出自定义异常
return a/b;
}
}
class ExceptionDemo4
{
public static void main(String[] args)
{
Demo d=new Demo();
try
{
int x=d.div(4,-1);
System.out.println("x=="+x);
}
catch (ArithmeticException e)
{
System.out.println("出现负数");
System.out.println(e.getMessage()); //by zero
System.out.println(e.toString());
e.printStackTrace(); //异常名称,异常信息,异常出现的位子
//其实jvm默认的异常处理机制,就是在调用printStackTrace方法
}
System.out.println("over");
}
}
//异常练习
/*
练习:有一个圆形和长方形
都可以获取面积,对于面积如果出现非法的数值,视为是获取面积出现问题
问题通过异常来表示
现有对这个程序进行基本设计
*/
class NoValueException extends RuntimeException
{
NoValueException(String message)
{
super(message);
}
}
interface Shape
{
void getArea();
}
class Rec implements Shape
{
private int len,wid;
Rec(int len,int wid)//throws NoValueException
{
if(len<=0 || wid<=0)
throw new NoValueException("出现非法值");
this.len=len;
this.wid=wid;
}
public void getArea()
{
System.out.println(len*wid);
}
}
class Circle implements Shape
{
private int radius;
public static final double PI=3.14;
Circle(int radius)
{
if(radius<=0)
throw new RuntimeException("非法值");
this.radius = radius;
}
public void getArea()
{
System.out.println(radius*radius*PI);
}
}
class ExceptionTest1
{
public static void main(String[] args)
{
Rec r=new Rec(3,4);
r.getArea();
Circle c = new Circle(-5);
c.getArea();
/*
try
{
Rec r=new Rec(-3,4);
r.getArea();
}
catch (NoValueException e)
{
System.out.println(e.toString());
}*/
System.out.println("over");
}
}
6. 包
6.1、package
在java中,管叫包,相当于文件夹。包里通常存放的是类文件,因为我们在编写程序的时候,难免会有类名相同的情况,就如我们人名一样。为了对类进行分类管理,java就有了包的出现,在不同包中可以有相同的类名,调用的时候连同包名一起就行。
包也是一种封装形式。在包中可以有很多类文件,但是只提供一个类文件,供外界使用。
6.2包的作用
1、为避免多个类重名的情况,如果出现两个相同名字的类,可通过包将两者区分,从而避免冲突。
2、对类文件进行分类管理,可以将相关的一些类放在同一个包中。
3、给类提供多层命名空间,如a包中的Demo.class文件,如果要创建Demo对象,就要在使用时加上a.如:a.Demo demo=new a.Demo();
4、包的出现可以将java的类文件和源文件相分离。
6.3、则
1、包必须写在程序的第一行。因为要先有包,才知道类文件的存放地方。
2、类的全称:包名.类名。
3、编译定义了包的程序文件时,在编译时要指定包的存储目录。
如:javac –d c:\mypack类名.java
6.4、包之间的访问
1、要访问其他包中的类,需要定义类的全称:包名.类名。
2、包如果不在当前路径,需要使用classpath设定环境变量,为JVM指明路径。
3、被访问的包中的类权限必须是public的。
4、类中的成员权限:public或者protected。protected是为其他包中的子类提供的一种权限。类公有后,被访问的成员也要公有才可以被访问。不同包中的子类可以直接访问父类中被protected权限修饰的成员。同一个包中,protected只作用为覆盖。
6.5、包的导入——import
1、可以简化类名。在调用其他包中的类时,需要写类的全称,也就是连同包名一起书写。当类存在多层包中时,如:haha.hehe.pack.Demo,使用import导入后,使用其类时,就可以不加包名了。导入格式如:import haha.hehe.pack.Demo;
2、一个程序文件中只有一个package,可以有多个import。import导入的是包中的类,不导入包中的包。
3、注意事项:
a,在导入包时,如果包中有很多类,可以使用通配符 *来替代包中的所有类。但是,建议不要使用通配符 *,因为将不需要使用的类导入后,会占用内存空间。所有在编写程序时,要使用包中的哪些类,就导入哪些类。
b,定义包名不要重复,可以使用url来完成定义,url是唯一的。如:package cn.itheima.Demo。
c,导入的不同包中有相同类时,必须写类的全名以区分,否则将报错