Java笔记(一)
1 static关键字---静态变量
1.1 什么时候定义静态变量呢?
当该成员变量的值,每一个对象都一致时,就对该成员变量进行静态修饰。
1.2 静态变量和成员变量的区别:
- 所属范围不同:静态变量所属类,成员变量所属对象;静态变量亦称类变量,成员变量亦称实例变量;
- 调用不同:静态变量可以被对象和类调用;成员变量只能被对象调用;
- 加载时期不同:静态变量随类的加载而加载,成员变量随着对象的加载而加载;
- 内存存储区域不同:静态变量存储在方法区中,成员变量存储在对内存中。
1
2 3 4 5 6 7 8 9 10 11 12 13 |
public Circle
{ private double radius; private static double pi = 3.14;//每一个圆对象中都存储一份,浪费内存空间,实现对象的共享,就要加入静态关键字修饰 Circle(double radius) { this.radius = radius; } double getArea() { return radius*radius*pi; } } |
1.3 静态代码块
主要是了解加载顺序
静态代码块:
特点:随着类的加载而执行,仅执行一次。
作用:给类进行初始化;
静态变量有两次初始化,一次默认初始化,一次是显示初始化,而静态代码块是在静态变量的显示初始化以后执行。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class Demo
{ static int x = 9; static //静态代码块 { System.out.println("类加载执行..."+x); } static void show() { static void show() { System.out.println("show run"); } } } class staticCodeDemo { public static void main(String[] args) { Demo show(); Demo show(); } } /*输出 类加载执行...+9 show run show run*/ |
1.4 构造代码块和局部代码块
构造代码块--只要创建对象就会被调用,给所有对象初始化,构造函数只给对应的对象针对性的初始化。在构造代码块中,可以定义不同构造函数的共性代码。
成员变量默认初始化和显示初始化。 构造代码块是在成员变量显示初始化后执行。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Demo
{ { //构造代码块 System.out.println("code run"); } Demo() { System.out.println("demo run"); } Demo(int x) { System.out.println("demo run"+x); } } |
局部代码块,可以控制局部变量的生命周期
1
2 3 4 5 6 7 8 9 10 11 12 13 |
class ConstructCodeDemo
{ public static void main(String[] args) { new Demo(); { //局部代码块,作用:就可以控制局部变量的生命周期 int x = 5; System.out.println("局部代码块..."+x); } System.out.println("over..."+x);//错误,x找不到 } } |
2 面向对象--对象的创建过程
- 加载Demo.class文件进方法区,并进行空间分配;
- 如果有静态变量,先默认初始化,显示初始化;
- 如果有静态代码块,要执行仅一次
- 通过对对象中的属性进行默认初始化;
- 构造函数内部:调用父类构造函数super(),成员变量显示初始化,构造代码块显示初始化,构造函数内容自定义初始化
- 对象的初始完毕后,将地址赋值给D。
3 设计模式--单例模式
3.1 单例模式
- 单例模式 :保证一个类的对象唯一性。比如多个程序要使用一个配置文件的数据,而且要实现数据共享和交换,必须将多个数据封装到同一个对象,而且多个程序操作的是同一个对象。
- 思路:一个类只要有构造函数,就可以产生多个对象。只要保证其他程序不建立对象即可。自己在本类中创建对象,供其他程序访问。
- 结果:构造函数私有化
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//---饿汉式
class Single { //创建一个本类对象 static Single s = new Single; //私有化构造函数 private Single(); public static Single getIntance() { return s;//静态函数只能访问静态成员 } } class SingleDemo { public static void main(String[] args) { //要想获取Single的对象,就要调用getIntance(),因为私有构造函数不可以用对象调用,只能用类对象调用且成员函数必须私有。 Single ss = Single.getIntance(); Single ss2 = Single.getIntance(); //以下方法可以但不建议。加入方法便于可控 Single ss3 = Single.s; Single ss4 = Single.s; } } //单例模式的延迟加载方式--懒汉式 class Single { private static Single s = null; //私有化构造函数 private Single(); public static Single getIntance() { if(s == null) s = new Single();//只有调用才会创建对象 return s; } } |
3.2 单例模式继承
为了提高复用,只建立一份代码。一个类只要和另一个产生关系就可以。
关系:继承。
解决:找到两者的共性类型,将需要提供复用的代码进行抽取,定义到一个共性类型的类中。
面向对象的另一个特征:继承
好处:提高代码的复用性,让类与类产生了关系。给另一个特征:多态,提供了前提
在JAVA中继承的体现:java中允许单继承,不支持多继承。
单继承:一个子类只能有一个父类;
多继承:一个子类可以又多个父类。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Person
{ String name; int age; } class Student extends Person { void study() { System.out.println("good good study"); } } class Worker extends Person { void work() { System.out.println("hard work"); } } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//多重继承
class A {} class B extends A {} class C extends A {} //多继承---JAVA中不存在该机制。因为可能存在不确定性因素 class A {} class B {} class C extends A,B {} |
4 继承
4.1 继承中成员变量
成员变量 特殊情况:
1、子类不允许直接访问父类的私有成员变量;
2、子父类中定义了相同名字的成员变量,都存在子类对象中,则应该如下操作:
用this来访问子类的成员变量,(因为先找局部内部的变量,找不到再向外找);
用super来访问父类的成员变量。(因为子类继承父类之后,会在子类中有一个父类的引用super)
this和super区别: this代表是本类的对象的引用,可以单独输出this地址;但是super代表的是父类的内存空间,不可以单独输出其地址。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//父类
class Fu { /*private int num1 = 3;*///父类中私有的内容子类不可以直接访问 int num = 3; } class Zi extends Fu { int num = 4; void show() { System.out.println("子类num"+this.num); System.out.println("父类num"+super.num); } } class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } } |
4.2 继承中的成员函数
特殊情况:
子父类中定义了相同名字的函数,结果是子类的函数在运行。
这种情况在子父类中,是函数的一个特性:override(重写覆盖,复写
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//父类
class Fu { void show() { System.out.println("fu show run"); } } class Zi extends Fu { void show() { System.out.println("zi show run"); } } class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); //结果是zi show run
} } |
重写什么时候用?
重写的注意事项:
1、子类覆盖父类,必须保证全要大于或者等于父类的权限;
2、静态覆盖静态
3、写法上要一致:函数的返回值类型,函数名,参数列表
4.3 继承-----构造函数
子父类中构造函数的特点:
当子父类都有构造函数时,执行顺序:
先执行了父类的构造函数,在执行子类的构造函数;
因为子类的所有的构造函数中的第一行都有一句隐式语句super();//默认调用父类中的空参数的构造函数;;
子类中的构造函数为什么有一句隐式super()呢?
原因:子类会继承父类的内容,所以子类在初始化,必须先到父类中去执行父类的初始化动作。当父类中没有
空参数构造函数时,子类的构造函数必须同时显示的super语句指定要访问的父类中的构造函数。
细节:
1、如果子类的构造函数第一行写了this调用了本类其他构造函数,那么super调用父类的语句还有吗?
没有的,因为this()或者super()只能定义在构造函数的第一行,因为初始化动作要先执行。
2、只要构造函数默认第一行都是super(),因而父类的构造函数也是有的。Java体系在设计中,定义了一个所有对象的父类
object。它是类层次结构的根类。
总结:
类中的构造函数默认第一行都有隐式的Super()语法,在访问父类中的构造函数,所以父类的构造函数既可以给自己的对象初始化,
也可以给自己的子类对象初始化。
如果默认的隐式super的语句没有对应的构造函数,必须在构造函数在通过this后者super的形式明确调用的构造函数。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
class ExtendsDemo3
{ public static void main(String[] args) { new Zi(); new Zi(6); } } class Fu { Fu() { System.out.println("Fu constructor run..."); } Fu(int x) { System.out.println("Fu constructor run..."+x); } } class Zi extends Fu { Zi() { System.out.println("Zi constructor run..."); } //super(); Zi(int x) { System.out.println("Zi constructor run..."+x); } } |
什么时候用super调用父类中的构造函数。
只要使用父类的制定初始化动作,就在子类中通过super(参数列表)格式化调用。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
class Person
{ private String name; private int age; public Person(String name, age) { this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public void getName() { return name; } public void setAge(int age) { this.age = age; } public void getAge() { return age; } } class Student extends Person { public Student(String name, int age) { super(name, age); } } class Worker extends Person { public Worker(String name, int age) { super(name, age); //必须明确super,否在会有不带参数的super,则父类没有不带参数的构造函数 } } |
继承的优点和缺点
优点
新的实现很容易,因为大部分是继承而来的
很容易修改和扩展已有的实现
缺点
打破了封装,因为基类向子类暴露了实现细节
白盒重用,因为基类的内部细节通常对子类是可见的
当父类的实现改变时可能要相应的对子类做出改变
不能在运行时改变由父类继承来的实现
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Fu
{ private void Sector(){}; //父类的实现改变,都会改变子类,且私有函数被暴漏
public void show() { Sector(); } } class Zi extends Fu { //重写 public void show() { System.out.println("haha"); } } |
4.4 禁止继承-final关键字
【final关键字】是一个修饰符,可以修饰类,方法,变量(成员变量,局部变量,静态变量)
【特点】
- final修饰的类是一个最终类,不可以再派生;如果类中从出现部分可以重写,部分不可以重写,就用最终化解决;
- final修饰的方法是最终方法,不可以重写;
- final修饰的变量是一个常量,只能被赋值一次;【只有当变量在程序中不被修改时,加上final修饰,增强阅读性】,final后面的变量必须用大写格式,或者多个词下划线隔开
5 抽象类
5.1 抽象类的细节问题
细节问题
1、抽象类一定是父类,不断的衍生子类;
2、抽象有构造函数但是不可以创建对象,虽然不能给自己的对象初始化,但是可以给子类对象初始化;
3、抽象类可以定义抽象方法,也可以为了不让该类创建对象而不定义抽象方法;
4、抽象关键字不可以和哪些关键字共存。
final -- private -- static
final修饰的类不可能再产生子类,而抽象类必须有子类;
private修饰的抽象方法是无法被子类覆盖的,而抽象方法是要子类进行覆盖的;
static能够直接被类名直接调用,而抽象方法是不可以直接被类名直接调用的;
5.2 面向对象--接口---定义与实现
当一个抽象类中的方法都是抽象的,则可以用接口来表示。
接口中的成员被限定为固定几种:
1、定义变量,但是变量必须有固定的修饰符修饰,public static final 所以接口中的变量也成为常量;
2、定义方法,也要有固定修饰符;public abstract,
接口中的成员都是公共的。
【接口的特点】
1、接口不可以创建对象;
2、子类必须覆盖掉接口中所有的抽象方法,子类才可以实例化;否则子类是一个抽象类;
【总结】定义子类去覆盖接口中的方法,子类必须和接口产生关系,类与类的关系是继承,类与接口之间的关系是实现。通过关键字implements
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
interface Demo//定义一个名称为Demo接口
{ public static final int NUM = 2; public abstact void show1(); public abstact void show2(); } class DemoImpl implements Demo { //重写接口中的方法 public void show1(){} public void show2(){} } class InterfaceDemo { public static void main(String[] args) { DemoImpl d = new DemoImpl; d.show1(); d.show2(); } } |
5.3 接口--多实现
【接口的体现】
解决多继承的弊端(当多个父类中有相同功能时,子类调用会产生不确定性)
---原因:在于多继承父类中功能主体,而导致调用运行时,不确定运行哪个主体内容。
解决方法:-将多继承这种机制在java中通过多实现完成的。(原因,因为接口中的功能都没有方法体,由子类来明确。)
1
2 3 4 5 6 7 8 9 10 11 12 |
interface A
{ void show(); } interface B { void show(); } class C implements A,B;//多实现,同时实现多个接口 { public void show(){}; } |
5.4 继承--同时多实现
【接口拓展】子类通过继承父类扩展功能,通过继承扩展的功能都是子类应该具备的基础功能。如果子类想要继续拓展其他类中的功能,则可以通过实现接口来完成。(接口的出现了避免了单继承的局限性)
接口的出现避免了单继承的局限性,父类中定义的事物的基本功能,接口中定义的事物拓展功能。
1
2 3 4 5 6 7 8 9 |
interface Inter
{ public void show(); } class Zi extends Fu implents Inter { } |
【接口出现后的一些小细节】
1、类与类之间就是继承(is a )关系,类与接口之间是实现(like a)关系
接口与接口之间是继承关系,而且可以多继承。
5.5 没有抽象方法的抽象类
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
interface Inter
{ public void show1(); public void show2(); public void show3(); public void show4(); } //定义子类,要使用第一种显示方式 //这个类创建对象就不需要,直接将其抽象化。 这就是没有抽象方法的抽象类 abstract class InterImpl implements Inter { //覆盖show1()方法; public void show1(){} //为了让该类实例化,还需要覆盖其他三个方法,虽然该类用不上 public void show2(){} public void show3(){} public void show4(){} } //出现问题:为了使用接口中的部分方法,而覆盖了全部方法,而且每一个子类都要这么做,复用性差。 //解决方法:将这些不用的方法单独抽取到一个独立的类中,让这个类去实现接口,并覆盖接口中的所有方法。如下程序所示 //如果有子类去使用显示1方法,让子类继承InterImpl实现类就可以。 //如果有子类去使用显示1方法,让子类继承InterImpl实现类就可以了 class InterImpl11 entends InterImpl { public void show1() { System.out.println("show1 run"); } } class InterImpl22 entends InterImpl { public void show2() { System.out.println("show2 run"); } } |
6 面向对象---接口
6.1 接口和抽象的区别
类负责描述的是事物的基本功能,接口负责描述事物的扩展功能。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class 犬
{ public void 吼叫(); public void 吃饭(); } interface 缉毒able { public abstract void 缉毒(); } class 缉毒犬 extends 犬 implements 缉毒able { public void 吼叫(){} public void 吃饭(){} public void 缉毒(){} } |
总结:
1】抽象类是描述事物的基本功能,可以定义非抽象的方法;接口中定义只能是抽象方法;
2】类与类之间是继承的关系,而类与接口之间是实现关系 like a关系。
6.2 多态好处和缺点
多态:【体现】父类的引用或者接口的引用指向了自己的子类对象;
1 Dog d = new Dog();//Dog对象的类型是Dog类型。 2 Animal a = new Dog();//Dog对象的类型右边是Dog类型,左边是Animal类型
好多:提高了程序的扩性‘
弊端:通过父类引用操作子类对象,只能使用父类中已有的方法,不能操作子类持有的方法。
前提:
1、必须有关系:继承,实现;
2、通常都有重写操作;
【子类的特有方法如何调用?】
Animal a = new Dog(); //Animal是父类型,new Dog是子对象。但是父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型),好处就是提高了扩展性,隐藏子类型。弊端:不能使用子类型的特有方法。
解决弊端方法:如果想使用子类的特有方法,只有子类型可以用,可以向下转型----强制转换。
1 Animal a = new Dog(); 2 a.eat(); 3 Dog d = (Dog)a;//将a转型到Dog类型---向下转型 4 d.lookhome();
注意:向上向下转型,最终都是子类对象做类型的变化。但是容易引发ClassCastException异常。所以再需要向下转型前,需要做类型的判断。关键字instanceof
1 if(a instanceof Cat)//a指向的对象的类型是cat类型 2 { 3 //将a转型为Cat类型‘ 4 Cat c = (Cat)a; 5 c.catchMouse(); 6 }
6.3 多态---成员变量的特点
- 成员变量
当子父类中出现同名的成员变量时,多态调用该变量时,
编译时期,参考的是引用型变量所属的类中是否有被调用的成员变量,没有则编译失败。
运行时期,也是引用型变量所属的类中是否有被调用的成员变量。【总】编译和运行都参考等号左边
1 class Fu 2 { 3 int num = 3; 4 } 5 class Zi extends Fu 6 { 7 int num = 5; 8 } 9 class Demo3 10 { 11 public static void main(String[] args) 12 { 13 Fu f = new Zi(); 14 System.out.println(f.num); 结果是3 15 Zi z = new Zi(); 16 System.out.println(z.num); 结果是5 17 } 18 }
- 成员函数【动态绑定到对象上】
编译:参考左边,如果没有,编译失败;
运行:参考右边的对象所属的类,编译看左边,运行看右边
1 class Fu 2 { 3 void show() 4 { 5 System.out.println("fu show"); 6 } 7 } 8 class Zi extends Fu 9 { 10 void show() 11 { 12 System.out.println("zi show"); 13 } 14 } 15 class Demo3 16 { 17 public static void main(String[] args) 18 { 19 Fu f = new Zi(); 20 System.out.println(f.show());//结果是 zi show 21 } 22 }
- 静态函数【静态绑定到类上】
编译运行都遵从左边。真正开发静态方法是不会被多态调用的。因为静态不是所属于对象,而动态是根据对象而言的。静态所属类。
class Fu { static void method() { System.out.println("fu static method"); } } class Zi extends Fu { static void method() { System.out.println("zi static method"); } } class Demo3 { public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.method());//输出结果是 fu static method
} }
6.4 面向对象--Object
Object类中的常用方法:Object类是所有类的根类,定义了所有对象都具备的功能。
Java中的区:本地区,栈区,代码区,静态区,堆区;
1
2 3 4 5 6 7 8 9 10 |
class ObjectDemo
{ public static void main(String[] args) { Person p1 = new Person(12); System.out.println(p1.toString()); //toString()返回一个字符串,最好覆盖重写toString() } } |
6.5 面向对象---内部类
当A类中的内容要被B类直接访问,而A类还需要创建B的对象,访问B的内容时,
这时,可以将B类定义到A类的内部。这样访问更为便捷;
将B称之为内部类(内置类,嵌套类)
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Outer 外部类
{ private int num = 4; public class Inner 内部类 //public一般不用再内部类,因为内部类已经封装到外部类中,不直接对外提供。 { void show() { System.out.println("num"+num); } //非静态内部类中不允许定义静态成员,仅允许在非静态内部类中定义,静态常量static final //如果想在内部类中定义静态成员,必须内部类也要被静态修饰。 } static class Inter2 //内部类被静态修时候,随着outer的加载而加载。可以认为静态内部类是一个外部类 { void show2() { System.out.println("Inner2 show2 run"); } System.out.println("Inner2 staticShow run");
}
{ Inner h = new Inner(); Outer.Inter in = new Outer.Inner(); //这是内部类的全名
h.show(); } } |
访问方式:内部类可以直接访问外部类中的所有成员,包括私有成员,而外部类要想访问内部类中的成员,必须创建内部类对象。
直接访问outer中的Inner内部类的非静态成员----直接创建内部类的对象,内部类作为对象为成员,应该先有个外部类对象,再有个内部类。 Outer.Inner in = new Outer().new Inner();
测试情况2:对静态内部类中的非静态成员进行调用,因为内部类是静态类,所以不需要创建Outer的对象,直接创建内部类对象就好了。
Outer.Inner2 in = new Outer. Inner2(); //j静态调用
如果静态内部类有静态成员,该如何访问呢?既然静态内部类已随外部类加载,而且静态成员随着类的加载而加载。
就不需要对象,直接用类名调用即可。
Outer.Inner2.staticShow();
- 为什么内部类就能直接访问外部类中的成员?
那是因为内部类其实持有了外部类的引用, 即外部类.this。 对于静态内部类不持有外部类.this,而是直接使用外部类名。
class Outer { int num = 3; class Inter { void show() { System.out.println(Outer.this.num); System.out.println(num); } } }
- 内部类其实也可以定义在外部类的局部位置上
内部类定义在局部时,只能访问final 修饰的局部变量,因为编译生产的class中直接操作那个最终值。但是局部类不能被成员修饰符修饰。
- 内部类时可以继承或者实现外部其他的类或者接口的
abstract class AbsDemo { abstract void show(); } class Outer { int num = 3; class Inner extends AbsDemo //内部类继承外部类,且会生成一个Outer$Inner.class文件,供外部调用, //注意这里的内部类不是private型,因而这个类可以对外提供
{ //重写抽象方法show,覆盖 void show() { System.out.println("num=" + num); } } public void method() { new Inner().show();//匿名对象 } } class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
- 若内部类被私有化之后,则需要通过父类或者接口的方式访问到内部类
abstract class AbsDemo { abstract void show(); } class Outer { int num = 3; private class Inner extends AbsDemo //内部类被封装,外部类都不可以对其访问,但是可以访问其父类 { //重写抽象方法show,覆盖 void show() { System.out.println("num=" + num); } } //获取内部类的对象 public AbsDemo getObject() { return new Inner(); } public void method() { new Inner().show();//匿名对象 } } class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); //如果Inner被private,可以通过父类型获取 Abstract a = Out.getObject();//多态,成员函数返回子类,但是可以赋值给父类 a.show(); } }
6.6 匿名对象
abstract class AbsDemo { abstract void show(); } class Outer { int num = 3; public void method() { /*不想创建具体的子类型,还想创建AbsDemo的 子类对象。怎么实现呢?没有子类型干脆,直 接使用父类型。但是父类是抽象类,如何可以new对象呢? 抽象类之所以不能创建对象,就是因为抽象方 法没有重写。 */ new AbsDemo() /*这是一个AbsDemo的子类对象,这是一个带着内容的子类对象。匿名对象类*/ { //重写抽象的show方法 void show() { System.out.println("num = "+ num); } }.show() } } class InnerClassDemo { public static void main(String[] args) { Outer out = new Outer(); out.method(); } }
在这里,简单的介绍一个内部类的使用。前提是内部类最多只有两个方法。
interface Inter { void show1(); void show2(); } class Outer { int num = 4; //在一个类使用一个接口的对象,可以通过内部类来实现 class Inner implements Inter { public void show1(); public void show2(); } //优化内部类使用接口对象,用匿名内部类来实现 Inter in = new Inter() { public void show1(){} public void show2(){} }; in.show1(); in.show2(); }
7 异常处理
7.1 异常处理的简要知识点
异常:
1、JAVA运行时发生的问题就是异常。
2、Java运行时发生的除了异常Exception还有错误Erro;
异常与错误的区别:
异常:通常发生可以有针对性的 处理方式的;
错误:通常发生后不会有针对性的处理方式的。Error的发生往往都是系统级别的问题,都是JVM所在系统发生的并反馈给JVM的。无法针对性处理。只能修改代码。
throw和throws的区别
1、throw用在函数内;
throw用在函数上;
2、throw抛出的是异常对象;
throws用于进行异常类的声明,后面异常类可以有多个,用逗号隔开
举个例子、
class NoShowException extends Exception { NoShowException(String message) { super(message); } } class Demo { void show(int num)throws NoShowException { if(num < 0) { throw new NoShowException(num+",数值是违法的"); } System.out.println("show...."+num); } } class ExceptionDemo9 { public static void main(String[] args) { Demo d = new Demo(); /* 因为调用到了声明异常的show方法,所以 调用者要给处理方式,要么继续声明, 要么捕获异常 */ try { d.show(); System.out.println("hello"); } catch (NoShowException ex) { System.out.println(ex.toString()); } } }
7.2 异常---finally的使用
/* 需求:有一些特定的代码无论异常是否发生, 都需要执行,因为异常会引发程序跳转,导致 有写语句执行不到。无法满足这个需求。异常捕获 处理 时java提供了解决方案。就是finally。这个代 码块中存放的代码都是一定会被执行的 */
特殊情况: 只有一种情况,finally不执行,就是System.exit(0);
class ExceptionDemo9 { public static void main(String[] args) { Demo d = new Demo(); /* 因为调用到了声明异常的show方法,所以 调用者要给处理方式,要么继续声明, 要么捕获异常 */ try { d.show(); } catch (NoShowException ex) { System.out.println(ex.toString()); //如果发生异常,处理完毕,功能结束 return; }
System.out.println("hello");//异常发生之后,因为有return语句,所以此语句不会执行,
finally { System.out.println("hello");//异常即使发生,也会执行该语句 } } }
总结:finally用处:
只要程序中使用到了具体的资源(数据库连接,IO资源,网络连接socket等)需要释放,都必须定义在finally中。你在定义程序,只要问题发生与否,指定程序都需要执行时,就定义finally中。
定义一个功能往数据中添加数据 void add (Data data)throws NoAddException { /*1、连接数据库;*/ try{ /*2、添加数据 添加数据时发生异常情况,throw new SQLException();程序跳转,就执行不 到断开连接。无论是否发生问题,都 需要执行断开连接的动作,从而释放资源*/ }catch(SQLException e) { /*解决数据库的问题; 同时将问题告诉调用者*/ throw new NoAddException(); } finally { /*3、断开连接*/ } }
7.3 try catch finally组合方式
1、try catch组合:
对代码进行异常检测,并对检测的异常传递给catch处理,异常捕获处理。
void show()//此时此处不需要throws { try { throw new Exception(); } catch(Exception e) { //若此处有一个throw e;语句,则throws必须含有,因为有throw要么有catch要么有throws } }
2、try finally组合:
对代码进行异常检测,检测到异常后因为没有catch,所以一样会被默认JVM抛出。异常时没有后捕获处理的。但是功能所开启资源需要进行关闭,所有finally,只为关闭资源。
void show()throws { try { throw new Exception(); } finally { } }
3、try catch finally组合:
检测异常并传递给catch处理,并定义资源释放;
try {} catch {} finally {}
异常在继承或者实现中的使用细节:★★★★★
- 子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明。
- 当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集。也可以声明单个父类异常
- 当被覆盖的方法没有异常声明时,子类覆盖时时无法声明异常的。举例如下
1 举例:父类存在这种情况,接口也有这种情况, 2 问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办? 3 解决方法:无法进行throws声明,只能catch的捕获。万一问题处理不了呢?catch中继续throw抛出,但是只能将异常转换成RuntimeException子类抛出。
Interface Inter { public void show(); } class Demo implement Inter { public void show() //这里不能声明异常throws { try{ throw new Exception(); }catch(Exception e) { code...; throw new RuntimeException("");// 告知调用者问题所在。 } } }
8 包package
8.1 包package的使用
对于多个类为了便于管理(类的同名情况),所以java提供了一个解决方案。
包机制:落实到操作系统上,就是文件夹。对Java的文件进行分文件夹管理。
例如: package mypack; //包名中的所有的字母都小写。
包的作用
- 对类文件进行管理。
- 给类文件提供了名称空间。
包的定义: 使用关键字 package。
包的生成: 对带有package定义的java文件进行指定类文件位置的编译方式。javac -d 目录 源文件。
例如:javac -d D:\class xxx.java 则会在D:class目录下生成文件夹 mypack,然后文件夹下生成xxx.class。
8.2 包与包之间的访问
DemoA.java
package packa; public class DemoA //为了使其他包内的类对其进行访问,则需要提高访问权限,即添加public { public void show()//因为要被其他包内的类进行访问,因而必须提高权限,即添加public { System.out.println("demoa show run"); } }
PackageDemo.java 要访问包pack中的类,而这个包在D:class目录下,则需要先 set classpath=包所在的父目录
class PackageDemo
{
public static void main(String[] args)
{
packa.DemoA d = new packa.DemoA();//访问DemoA.java中的类
DemoA d = new DemoA();
d.show();
}
}
总结:
包与包之间的类在访问时,被访问的类以及成员都必须public修饰。
注意:被public修饰的类或者接口,所属的java文件名必须和类或者接口名称一致。
8.3 包之间的继承关系
包与包之间继承。父类可以给其他包中的子类提供一个特殊的权限 protected。只有继承为子类后,
就可以访问的权限
public | protected | default | private | |
一个类中 | ok | ok | ok | ok |
一个包中 | ok | ok | ok | |
子类中 | ok | ok | ||
不同包中 | ok |
包与包之间访问只有两种权限可以用,public protected(该权限只能给不同包中的子类使用)。
包的出现,导致类的名称过长书写不方便,咋办?
可以通过指定的关键字解决:import :导入。
import作用简化类名书写,省略包名。
特殊情况一: packa\packaa\DemoAA.class\DemoA.class
import packa.*;//明确类使用的类所属的包是packa。不会导入packa中子包中的类。
如果要使用DemoAA。
import packa.packaa.*;
new DemoAA();
特殊情况二:不同包中有了相同名称的类。使用该类时必须指定包名。
packa\Demo.class packb\Demo.class import packa.Demo; import packb.Demo; new packa.Demo();
在命令行中,添加 jar包
jar -cvf haha.jar pack //就是将pack包压缩到hahha.jar归档文件中。
使用方法:
就是对jar进行设置path。
set classpath =.\haha.jar