--------------android培训、java培训、期待与您交流! --------------
一、内部类
在类中定义一个类,则将在类中定义的类称为内部类。内部类可分为成员内部类、局部内部类以及静态内部类和匿名类。
1、内部类访问规则及格式
内部类访问规则:(1)内部类可以直接访问外部类中的成员,包括私有成员。 之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用。格式:外部类名.this(2)外部类要访问内部类中的成员必须要建立内部类的对象。内部类访问格式: (1)当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中直接建立内部类对象。 格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inner in = new Outer().new Inner();
(2)当内部类在成员位置上,就可以被成员修饰符所修饰。 比如,private:将内部类在外部类中进行封装
static:内部类就具备了static的特性,成为了静态内部类。
示例:
//外部类
class Outer
{
private int x = 9;//外部类成员变量
//内部类
class Inner
{
int x = 6;//内部类成员变量
void function()
{
int x = 3;//局部变量
System.out.println("内部类方法中局部变量 :"+x);
System.out.println("内部类成员变量 :"+this.x);
System.out.println("外部类成员变量:"+Outer.this.x);//内部类可以直接访问外部类,包括外部类私有。
}
}
void method()
{
Inner in = new Inner();//外部类建造内部类的对象,用来访问内部类。
in.function();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
/*建立外部类对象访问外部类方法
* 外部类方法中又建立内部类对象,从而访问了内部类中的成员方法。
*/
Outer out = new Outer();
out.method();
//直接访问内部类中的成员。
Outer.Inner in = new Outer().new Inner();
in.function();
}
}
2、静态内部类
当一个内部类位于外部类的成员位置上,并被static关键字修饰,这个类就成为了静态内部类。
(1)当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。
//外部类
class Outer
{
private static int x = 9;
private int y=10;
//静态内部类
static class Inner
{
void function()
{
System.out.println(x);//静态内部类只能直接访问外部类的静态成员x
//System.out.println(y);//外部类的非静态成员y则不能被静态内部类直接访问
}
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
new Outer.Inner().function();//9
}
}
(2)在外部其他类中,如何直接访问static内部类的非静态成员呢?
格式:new Outer.Inner().function();
//外部类
class Outer
{
private static int x = 9;
//静态内部类
static class Inner
{
void function()
{
System.out.println(x);
}
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
new Outer.Inner().function();//直接访问静态内部类中的非静态方法。
}
}
(3)在外部其他类中,如何直接访问static内部类的静态成员呢?
格式:outer.Inner.function();
//外部类
class Outer
{
private static int x = 9;
//静态内部类
static class Inner
{
static void function()
{
System.out.println(x);
}
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
Outer.Inner.function();//直接访问静态内部类中的静态方法。
}
}
(4)注意:当内部类中定义了静态成员,该内部类必须是static的。
当外部类中的静态方法访问内部类时,内部类也必须是static的。
3、内部类定义原则
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
因为内部事物在使用外部事物的内容。
例如:人体和心脏,人体是外部类,心脏是内部类,心脏可以直接访问人体的成员。
class Body
{
private class Heart
{
void jump{
System.out.println("心跳");
}
}
public void show()
{
new Heart().jump();
}
}
4、局部内部类
内部类定义在局部时,就成为了局部内部类。
(1)不可以被成员修饰符修饰
(2)可以直接访问外部类中的成员,因为还持有外部类中的引用。
但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。
原因:
局部内部类的生命周期要长于其所在方法中的局部变量和参数的生命周期。一个方法运行结束,其局部变量就随之被回收,而局部内部类的对象还存在,只有当不再引用该对象时,它才会被回收。当局部变量被回收了,局部内部类的对象存在而且依然在访问这个局部变量,但是局部变量已经被回收不存在了,所以出现了矛盾。
当局部变量被final修饰,则其就就会变成局部内部类的一个成员,就不存在生命周期不一致的矛盾问题。
class Outer{
int x = 3;
void method(final int a)
{
int y = 4;
//局部内部类
class Inner
{
void function()
{
System.out.println(x);//局部内部类还持有外部类的引用,可以访问外部类成员。
//局部内部类不能访问其所在的局部中的变量,只能访问被final修饰的局部变量
System.out.println(a);
//System.out.println(y);
}
}
new Inner().function();
}
}
public class InnerClassDemo {
public static void main(String[] args) {
Outer out = new Outer();
out.method(8);
}
}
5、匿名内部类
(1)匿名内部类其实就是内部类的简写格式。
(2)定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口。
(3)匿名内部类的格式:
new 父类或者接口()
{
定义子类的内容
}
(4)其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。可以理解为带内容的对象。
(5)匿名内部类中定义的方法最好不要超过3个。
例:
内部类继承了抽象类,这是定义匿名内部类的前提。
//抽象类
abstract class AbsDemo
{
abstract void show();//抽象show方法
}
class Outer
{
//内部类继承抽象类
class Inner extends AbsDemo
{
int num = 8;
void show()//具体实现抽象类中的show方法
{
System.out.println("show :"+num);
}
}
public void function()
{
new Inner().show();//外部类新建内部类对象访问show方法
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
new Outer().function();
}
}
将其改写为匿名内部类
//抽象类
abstract class AbsDemo
{
abstract void show();//抽象show方法
}
class Outer
{
public void function()
{
//匿名内部类
new AbsDemo()
{
int num = 9;
void show()
{
System.out.println("show :"+num);
}
}.show();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
new Outer().function();
}
}
interface Inter{代码分析:
void method();
}
class Test{
//补足代码。通过匿名内部类。
}
class InerClassTest{
public static void main(String[] args) {
Test.function().method();
}
}
InerClassTest的主函数中运行一句Test.function().method();
Test是个类,Test.function()表示Test没有创建对象就可以直接调用function,这说明function()是Test中的一个静态函数。
已知还有一个接口类Inter,Inter中有个抽象方法method,可以在function方法中写一个匿名内部类继承Iner并实现method方法。
Test.function().method()表明method被对象调用,那么function()需要返回一个Inter类型的匿名子类对象就可以了。
Test.function().method();相当于:
new Inter()
{
public void method()
}.method();
实现代码如下:
interface Inter{
void method();
}
class Test{
static Inter function(){
return new Inter (){
public void method(){
System.out.println("method run");
}
};
}//function方法返回匿名匿名子类对象
}
class InerClassTest{
public static void main(String[] args) {
Test.function().method();
}
}
二、异常处理
1、异常概述
异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。
其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分:两种:一种是严重的问题,一种非严重的问题。
(1)严重的问题:java通过Error类进行描述。
对于Error一般不编写针对性的代码对其进行处理。
(2)非严重的问题:java通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都具有一些共性内容。
比如:不正常情况的信息,引发原因等。
Throwable
|--Error
|--Exception
例:给定算术式3/0,在算术中这是错误的,程序执行时则会抛出算术异常ArithmeticException
public class ExceptionDemo {
public static void main(String[] args) {
int result=3/0;
System.out.println(result);
/*程序运行结果:
* Exception in thread "main" java.lang.ArithmeticException: / by zero
* main函数中有异常 算术异常:/除零
* at test.ExceptionDemo.main(ExceptionDemo.java:6)
* 在第6行
*/
}
}
2、异常try-catch
(1)异常的处理
java提供了特有的语句进行处理。
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
(2)对捕获到的异常对象进行常见方法操作。
toString() 返回此 throwable 的简短描述
getMessage() 返回此 throwable 的详细消息字符串。
printStackTrace() 将此 throwable 及其追踪输出至标准错误流。
例;
public class ExceptionDemo {
public static void main(String[] args){
try{
int result=3/0;
System.out.println(result);
}
catch(Exception e){
System.out.println("出现除零错误!");
System.out.println(e.getMessage());// /by zero
System.out.println(e.toString());// 异常名称 : 异常信息。java.lang.ArithmeticException: / by zero
e.printStackTrace();//异常名称,异常信息,异常出现的位置。其实jvm默认的异常处理机制,就是在调用printStackTrace方法。
//打印异常的堆栈的跟踪信息。
}
finally{
System.out.println("运行完毕");
}
}
}
3、异常声明throws
在函数上声明异常。
便于提高安全性,让调用者进行处理。不处理编译失败。
public class ExceptionDemo {
///在功能上通过throws的关键字声明了该功能有可能会出现问题。
public static int div(int a,int b)throws Exception{
return a/b;
}
//如若调用可能产生异常的功能而不进行异常捕捉处理,调用的主体也可以将异常抛出给虚拟机来处理
public static void main(String[] args)//throws Exception
{
/*在主函数中调用可能会出现问题的功能时,如若不进行异常处理,则会编译失败,
* 强制使用者对功能进行异常处理,提高程序安全性。
*/
try{
int result=div(3,0);
System.out.println(result);
}
catch(Exception e){
System.out.println(e);
}
finally{
System.out.println("运行完毕");
}
}
}
4、多异常处理
对多异常的处理。
(1)声明异常时,建议声明更为具体的异常。这样处理的可以更具体。
(2)对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
(3)建立在进行catch处理时,catch中一定要定义具体处理方式。不要简单定义一句 e.printStackTrace(),也不要简单的就书写一条输出语句。
public class ExceptionDemo {
//功能中可能会出现多个异常,则功能可以针对多个可能发生的问题抛出对应的多个具体异常
public static int method(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int arr[] = new int[a];
System.out.println(arr[6]);//可能发生角标越界异常
return a/b;//可能发生除数为零异常
}
public static void main(String[] args)
{
try{
int result=method(6,1);
System.out.println(result);
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println("数组角标越界!");
System.out.println(e);
}
catch(ArithmeticException e){
System.out.println("除数为零!");
System.out.println(e);
}
catch(Exception e){
System.out.println(e);
}
finally{
System.out.println("运行完毕");
}
}
}
5、自定义异常
(1)因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。
所以对于这些特有的问题可以按照java的对问题封装的思想,将特有的问题,进行自定义的异常封装,这就是自定义异常。
(2)如何进行自定义异常:必须是自定义类继承Exception。
继承Exception原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。
他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点,只有这个体系中的类和对象才可以被throws和throw操作。
需求:在本程序中,对于除数是负数,也视为是错误的是无法进行运算的。
那么就需要对这个问题进行自定义的描述。
//自定义一个负数异常类继承异常类
class FuShuException extends Exception {
private int value;
FuShuException(String msg){
super(msg);
}
FuShuException(String msg,int value){
super(msg);
this.value = value;
}
public int getValue(){
return value;
}
}
class Demo{
//函数内出现异常,函数上需要声明。
int div(int a,int b) throws FuShuException {
if(b<0){
throw new FuShuException("除数是负数!",b);
//通过throw关键字手动抛出一个自定义异常对象,因为jvm不能识别自定义异常并进行抛出。
}
return a/b;
}
}
class ExceptionDemo {
//调用了可能会出现异常的函数时,那么调用主体就必须进行内部try catch或抛出处理
public static void main(String[] args)//throws Exception
{
Demo d = new Demo();
try{
int x = d.div(8,-6);
System.out.println("x="+x);
}
catch (FuShuException e){
System.out.println(e.toString());
System.out.println("错误的数是:"+e.getValue());
}
}
}
6、throw和throws的区别
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try catch处理,要么在函数上声明让调用者处理。
一般情况下,函数内出现异常,函数上需要声明。
throws和throw的区别:
(1)throws使用在函数上。
throw使用在函数内。
例:
//自定义一个负数异常类继承异常类(2)throws后面跟的异常类。可以跟多个。用逗号隔开。
class FuShuException extends Exception {}
class Demo{
//throws在函数上使用。
int div(int a,int b) throws FuShuException {
if(b<0){
throw new FuShuException("除数是负数!",b); //throw在函数内使用
}
return a/b;
}
}
throw后跟的是异常对象。
例:
throws:
public int method(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException//throws后面跟的异常类。可以跟多个
{
int arr[] = new int[a];
System.out.println(arr[6]);//可能发生角标越界异常
return a/b;//可能发生除数为零异常
}
throw:
int div(int a,int b) throws FuShuException {
if(b<0){
throw new FuShuException("除数是负数!",b); //throw后跟的是一个异常对象。
}
7、RuntimeException
Exceptoin中有一个特殊的子类异常RuntimeException 运行时异常。
(1)如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。
原因:之所以不用在函数声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
(2)如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;
自定义异常时:如果该异常的发生,无法在继续进行运算,
就让自定义异常继承RuntimeException。
对于异常分两种:
(1)编译时被检测的异常。
(2)编译时不被检测的异常(运行时异常。RuntimeException以及其子类)
//自定义一个负数异常类继承运行时异常类
class FuShuException extends RuntimeException {
FuShuException(String msg){
super(msg);
}
}
class Demo{
//在函数上声明了异常,调用者不用进行异常处理,编译也能通过因为函数上声明的异常是继承的运行时异常类。
int div1(int a,int b)throws ArithmeticException
{
return a/b;
}
//函数中抛出异常,但函数上不用声明异常也能编译通过,因为函数中的异常是继承的运行时异常类
int div2(int a,int b)//throws FuShuException
{
if(b<0)
throw new FuShuException("除数是负数!");
return a/b;
}
}
class ExceptionDemo {
public static void main(String[] args)//throws Exception
{
Demo d = new Demo();
int x = d.div1(8,0);
int y = d.div2(8, -6);
System.out.println("x="+x);
System.out.println("y="+y);
}
}
8、异常练习
需求:
毕老师用电脑上课。开始思考上课中出现的问题。
比如问题是:电脑蓝屏,电脑冒烟。
要对问题进行描述,封装成对象,编写自定义异常。
可是当冒烟发生后,出现讲课进度无法继续。
出现了讲师的问题:课时计划无法完成。
代码:
//自定义异常
//电脑蓝屏异常
class LanPingException extends Exception
{
LanPingException(String message)
{
super(message);
}
}
//电脑冒烟异常
class MaoYanException extends Exception
{
MaoYanException(String message)
{
super(message);
}
}
//课程中断异常
class NoPlanException extends Exception
{
NoPlanException(String msg)
{
super(msg);
}
}
class Computer
{
private int state = 3;
public void run()throws LanPingException,MaoYanException//声明异常让调用者处理
{
//电脑运行方法内抛出可能发生的异常
if(state==2)
throw new LanPingException("蓝屏了");
if(state==3)
throw new MaoYanException("冒烟了");
System.out.println("电脑运行");
}
public void reset()
{
state = 1;
System.out.println("电脑重启");
}
}
class Teacher
{
private String name;
private Computer cmpt;
Teacher(String name)
{
this.name = name;
cmpt = new Computer();
}
public void prelect()throws NoPlanException//将自身不能处理的课程中断进行声明
{
//老师针对可能会遇到的电脑异常进行try catch处理
try
{
cmpt.run();
}
catch (LanPingException e)
{
cmpt.reset();
}
catch (MaoYanException e)
{
test();
throw new NoPlanException("课时无法继续"+e.getMessage());//老师不能解决电脑冒烟异常,于是抛出自身的课程中断异常
}
System.out.println("讲课");
}
public void test()
{
System.out.println("练习");
}
}
class ExceptionTest
{
public static void main(String[] args)
{
Teacher t = new Teacher("毕老师");
//boss针对老师讲课可能出现的课程中断异常进行try catch处理。
try
{
t.prelect();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
finally代码块:定义一定执行的代码。常用于关闭资源。
class FuShuException extends Exception {输出:
FuShuException(String msg){
super(msg);
}
}
class Demo{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw new FuShuException("除数是负数!");
return a/b;
}
}
class ExceptionDemo {
public static void main(String[] args)
{
Demo d = new Demo();
try{
int x = d.div(8,-1);
System.out.println("x="+x);
}
catch(FuShuException e){
System.out.println(e);
return;
//System.exit(0);若该语句执行后程序则会退出,则finally中的语句则不会执行。
}
//finally中存放的是是一定会执行的代码
finally{
System.out.println("运行完毕!");
}
}
}
FuShuException: 除数是负数!
运行完毕!
10、处理语句其他格式
第一个格式:
try{ }
catch (){ }
第二个格式:
try{ }
catch (){ }
finally{ }
第三个格式:
try{ }
finally{ }
记住一点:catch是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常。那么必须声明。
class Demo
{
public void method()throws Exception
{//异常可以交给调用者处理,但防止调用者对相关资源不采取关闭动作,事先用finally实现关闭资源。
try
{
throw new Exception();
}
finally
{
//关资源。
}
}
}
11、覆盖时的异常特点
异常在子父类覆盖中的体现;
(1)子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
(2)如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
(3)如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。
/*A异常是父类,B异常是A的子类。
C异常不是A异常的子类,且C异常和A异常同是Exception的子类。
Exception
|--AException
|--BException
|--CException
*/
class AException extends Exception{ }
class BException extends AException{ }
class CException extends Exception{ }
class Fu
{
void show()throws AException{ }//父类show方法抛出A异常
}
class Zi extends Fu
{
void show()throws BException{ }
//子类show方法只能抛出父类方法抛出的的A异常或A异常的子类,例如B异常。但不能抛出C异常,C异常不是A异常的子类。
}
class Test
{
void function(Fu f)
{
try
{
f.show();
}
catch (AException e){ }
/*分析:
* 例如function方法带有父类引用参数,当function方法接收到父类对象,f.show方法就是父类的show方法
* 由于父类的show方法会抛出A异常,则使catch接收A异常对象进行处理。
*
* 若function方法接收到子类对象,即Fu f=new Zi();即变成了多态,f.show()方法就变成了子类的show方法。
* (1)当子类的show方法抛出的异常是父类方法抛出的的A异常或A异常的子类,那么catch (AException e)则可以处理异常,
* 因为AException可以处理A异常及其子类。
* (2)当子类的show方法抛出的异常 不是 父类方法抛出的的A异常或A异常的子类,那么catch (AException e)则不能处理异常,
* 因为AException只能处理A异常及其子类,不能处理其它的异常。
*/
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Test t = new Test();
t.function(new Zi());
}
}
三、Package
1、Package(包)
(1)对类文件进行分类管理(相当于系统中的文件夹)
(2)给类提供多层命名空间
例如:A包和B包中各有一个Demo.class文件,现在要运行一个Demo.class文件,
就不能写java Demo,必须要指定一个包名下的类文件,例如写成java A.Demo
(3)写在程序的一行
(4)类名的全称是包名.类名
(5)包也是一种封装形式
//包名中所有的字母都要小写
package pack.test;//pack.test是多层目录,pack包中有test包,test包中有类文件
public class PackageDemo {
public static void main(String[] args) {
System.out.println("Hello Package!");
}
}
注意:
编译一个java文件时,java文件中写有包的语句,但当前目录中不存在有关包目录,则会编译失败,找不到有关文件。
可以在编译时加参数:java -d "指定存放位置" java文件名
这样java虚拟机会在指定位置生成包和class文件。
包与包之间访问:
(1)包与包之间进行访问,被访问的包中的类以及类中的成员,需要public修饰。
(2)不同包中的子类还可以直接访问父类中被protected权限修饰的成员。
(3)包与包之间可以使用的权限只有两种,public protected。
public protected default private
同一个类中 ok ok ok ok
同一个包中 ok ok ok
子类 ok ok
不同包中 ok
2、import(导入)
为了简化类名的书写,使用一个关键字,import.
import 导入的是包中的类。
建议,不要写通配符 * ,需要用到包中的哪个类,就导入哪个类。
例:
A包中有Demo1.class和Demo2.class等等
现在要使用Demo1这个类
加通配符:
import A.*;这条语句导入了A包中所有的类,但不建议使用,需要用到包中的哪个类,就导入哪个类。
不加通配符:
import A.Demo1这条语句就只导入了Demo1类
3、jar包
方便项目的携带。
方便使用,只要在classpath设置jar路径即可。
数据库驱动,SSH框架等到是以jar包体现的。
选项包括:
-c 创建新的归档文件
-t 列出归档目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有的归档文件
-v 在标准输出中生成详细输出
-f 指定归档文件名
-m 包含指定清单文件中的清单信息
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点
-0 仅存储; 不使用情况任何 ZIP 压缩
-M 不创建条目的清单文件
-i 为指定的 jar 文件生成索引信息
-C 更改为指定的目录并包含其中的文件
如果有任何目录文件, 则对其进行递归处理。
清单文件名, 归档文件名和入口点名称的指定顺序
与 'm', 'f' 和 'e' 标记的指定顺序相同。
示例 1:将两个类文件归档到一个名为 classes.jar 的归档文件中:
jar cvf classes.jar Foo.class Bar.class
示例 2:使用现有的清单文件 'mymanifest' 并
将 foo/ 目录中的所有文件归档到 'classes.jar' 中:
jar cvfm classes.jar mymanifest -C foo/。