内部类
- 将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
- 访问特点:
- 内部类可以直接访问外部类中的成员,包括私有成员。
- 而外部类要访问内部类中的成员必须要建立内部类的对象。
内部类访问规则
- 内部类可以直接访问外部类中的成员,包括私有。
- 之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this
- 外部类要访问内部类,必须建立内部类对象。
访问格式:
- 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。可以直接建立内部类对象。
- 格式
- 外部类名.内部类名 变量名 = 外部类对象.内部类对象;
- Outer.Inner in = new Outer().new Inner();
- 当内部类在成员位置上,就可以被成员修饰符所修饰
- 比如,private:将内部类在外部类中进行封装。
- static:内部类就具备static的特性
- 当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。
- 在外部其他类中,如何直接访问static内部类呢?
- Outer.Inner.function();
注意:
- 当内部类中定义了静态成员,该内部类必须是static的。
- 当外部类中的静态方法访问内部类时,内部类也必须是static的。
package 内部类1;
class Outer
{
private int x=10;
class Inner//内部类
{
int x=1;//内外有同名变量时
void function(){
System.out.println("inner:"+Outer.this.x);
//用"外部类名"调用外部类的成员变量供内部类使用
}
}
/*
class Inner
{
void function(){
System.out.println("inner:"+x);//内部类可以直接使用外部类的成员变量
}
}
*/
void method()
{
Inner in=new Inner();//外部类使用内部类,需要创建对象
in.function();
}
}
public class InnerClassDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer out=new Outer();
out.method();
}
}
输出:
inner:10
//直接访问内部类的成员。
Outer.Inner in=new Outer().new Inner();
in.function();
内部类可以使用 private 修饰
内部类定义在局部时
- 不可以被成员修饰符修饰
- 可以直接访问外部类中的成员,因为还持有外部类中的引用。
- 但是不可以访问它所在的局部中的变量。只能访问被 final 修饰的局部变量。
class Outer
{
int x=3;
void method()
{
final int y=4;
class Inner
{
void function()
{
System.out.println(y);
}
}
new Inner().function();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
new Outer().method();
}
}
匿名内部类
- 匿名内部类其实就是内部类的简写格式。
- 定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。
- 匿名内部类的格式: new 父类或者接口(){定义子类的内容}
- 其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。可以理解为带内容的对象。
匿名内部类中定义的方法最好不要超过3个。
abstract class AbsDemo { abstract void show(); } class Outer { int x=3; public void function() { new AbsDemo()//匿名内部类 { void show() { System.out.println("x==="+Outer.this.x); } }.show(); } } class Test { public static void main(String [] args) { Outer ot=new Outer(); ot.function(); } }
静态方法获取内部类
题目:
interface Inner
{
public abstract void method();
}
class Outer
{
//补充代码
static function()
{
}
}
class InnerDemo
{
public static void main(String [] args)
{
Outer.function().method();
}
}
实现
interface Inner
{
public abstract void method();
}
class Outer
{
static Inner function()
{
return new Inner()
{
public void method()
{
System.out.println("Inner method.");
}
};
}
}
class InnerDemo
{
public static void main(String [] args)
{
Outer.function().method();//调用类静态方法得到一个内部类引用,并使用他的方法method();
}
}
异常
1.异常概述
异常:就是程序在运行时出现不正常情况
异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。
其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分:
- 严重的问题
- 非严重的问题
对于严重的,java通过Error类进行描述.
对于Error一般不编写针对性的代码对其进行处理。
对于非严重的,java通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
2.异常的处理 try catch
java提供了特有的语句进行处理。
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
对捕获到的异常对象进行常见方法操作
String getMessage();获取异常信息
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
public class ExceptionDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d=new Demo();
try
{
int x=d.div(4, 0);
System.out.println("x=="+x);
}
catch(Exception e)
{
System.out.println("除零了");
System.out.println(e.getMessage());// /by zero;
System.out.println(e.toString());// 异常名称:异常信息。
e.printStackTrace();//异常名称,异常信息,异常出现的位置
//其实jvm默认的异常处理机制,就是在调用printStackTrace()方法,打印异常的堆栈的跟踪信息。
}
System.out.println("Over");
}
}
输出:
除零了
/ by zero
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zeroOver
at 异常.异常概述.Demo.div(ExceptionDemo.java:7)
at 异常.异常概述.ExceptionDemo.main(ExceptionDemo.java:18)
3.异常声明throws
class Demo
{
int div(int a,int b)throws Exception//在功能上通过throws的关键字声明了该功能有可能会出现问题。
{
return a/b;
}
}
public class ExceptionDemo
{
public static void main(String[] args)throws Exception //main把Exception抛出给虚拟机处理
{
// TODO Auto-generated method stub
Demo d=new Demo();
int x=d.div(4, 0);
System.out.println("x="+x);
}
}
也可以去掉main的throws 自己使用try catch处理异常
try
{
int x=d.div(4, 0);
System.out.println("x=="+x);
}
catch(Exception e)//Exeption e = new ArithmeticException();
{
e.printStackTrace();//异常名称,异常信息,异常出现的位置
//其实jvm默认的异常处理机制,就是在调用printStackTrace()方法,打印异常的堆栈的跟踪信息。
}
4.对多异常的处理
- 声明异常时,建议声明更为具体的异常,这样处理的可以更具体。
- 对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。
- 如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面
建议在catch处理时,catch中一定要定义具体处理方式。
不要简单定义一句 e.printStackTrace();
也不要简单的就书写一条输出语句。
class Demo
{
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException//丢出指定异常
{
int[] arr = new int[a];
System.out.println(arr[4]);
return a/b;
}
}
public class ExceptionDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d=new Demo();
try
{
int x=d.div(4, 0);
System.out.println("x=="+x);
}
//捕获指定异常
catch(ArithmeticException e)//Exeption e = new ArithmeticException();
{
System.out.println(e.toString());
System.out.println("被零除了");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e.toString());
System.out.println("角标越界");
}
catch(Exception e)
{
System.out.println(e.toString());
}
System.out.println("Over");
}
}
5.自定义异常
因为项目中会出现特有的问题,而这些问题未被java所描述并封装对象。
所以对于这些特有的问题可以按照java的对问题封装的思想。
将特有的问题,进行自定义的异常封装。
需求:在本程序中,对于除数是-1,也视为是错误的是无法进行运算的。
那么就需要对这个问题进行自定义的描述。
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
要么在内部try catch处理。
要么在函数上声明让调用者处理。
一般情况下函数内出现异常,函数上需要声明。
如何定义异常信息?
自定义异常:
必须是自定义类继承 Exception
继承Exception原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。
他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。
只有这个体系中的类和对象才可以被throws和throw操作
package 异常.自定义异常;
class FuShuException extends Exception
{
private int value;
FuShuException()
{
super();
}
FuShuException(String msg)
{
super(msg);
}
FuShuException(String msg,int value)
{
super(msg);
this.value=value;
}
int getValue()
{
return this.value;
}
}
class Demo
{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw new FuShuException("出现负数.",b);
return a/b;
}
}
public class ExceptionDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d=new Demo();
try
{
d.div(5, -2);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("负数是:"+e.getValue());
}
}
}
输出:
异常.自定义异常.FuShuException: 出现负数.
负数是:-2
throws和throw的区别
throws使用在函数上。
throw使用在函数内。
throws后面跟的异常类,可以跟多个。用逗号隔开。
throw后面跟的是异常对象。
RuntimeException
Exception中有一个特殊的子类异常RuntimeException运行时异常。
RuntimeException的子类使用throw在函数内抛出,不需要在函数上使用throws声明。编译一样通过。
并且在调用函数内不用try catch处理。编译一样通过。
之所以不用在函数声明,是因为不需要让调用者处理。
当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
自定义异常时:如果该异常的发生,无法在继续进行运算,就让自定义异常继承RuntimeException.
对于异常分两种:
1. 编译时被检测的异常。
2. 编译时不被检测的异常(运行时异常。RuntimeException以及其子类)
package 异常.RuntimeException;
class FuShuException extends RuntimeException
{
FuShuException(String msg)
{
super(msg);
}
}
class Demo
{
int div(int a,int b)
{
if(b<0)
throw new FuShuException("出现了除数为负数");
if(b==0)
throw new ArithmeticException("被零除了 /0");
return a/b;
}
}
public class ExceptionDemoR {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d=new Demo();
int x=d.div(4, -1);
System.out.println("x="+x);
}
}
Exception in thread “main” 异常.RuntimeException.FuShuException: 出现了除数为负数
at 异常.RuntimeException.Demo.div(ExceptionDemoR.java:15)
at 异常.RuntimeException.ExceptionDemoR.main(ExceptionDemoR.java:27)