Java基础-面向对象
面向对象进阶(续)
1、面向对象(内部类访问规则)
内部类:将一个类定义在另一个类里面,类里面的那个类就称为内部类(内置类、嵌套类) 访问特点:
(1)、内部类可以直接访问外部类中成员,包括私有成员。
(2)、而外部类要访问内部类中的成员必须要建立内部类的对象。
Eg:
public class Outer
{
int x = 3;//即使加上private,内部类一样可以访问
void method()
{
Inner in = new Inner ();
in.function();
//System.out.println(x);
}
class Inner //内部类
{
int x = 4 ;
void function()
{
int x = 5;
System.out.println("Inner:"+x+this.x+Outer.this.x);
}
}
}
class InnerClassDemo
{
public static void main(String []args)
{
/*
Outer out = new Outer();
out.method();
*/
//下面代码替换以上代码,效果一样。
Outer.Inner in = new Outer().new Inner();
in.function();
//要明白,之所以可以直接访问外部类的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this
}
}
程序结果:Inner:543
2、面向对象(静态内部类)
访问格式
(1)、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象。 格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象 例如:Outer.Inner in = new Outer().new Inner();
(2)、当内部类在成员位置上,就可以被成员修饰符所修饰。比如:内部类具备static的特性。 Eg:
class Outer
{
private int x = 3 ;
static class Inner //静态类
{
void function()
{
System.out.println("inner:"+x); //错误,静态内部类不能访问外部类的成员,除非外部类成员也是静态的。
}
}
}
class OuterClassDemo
{
public static void main(String[]args)
{
Outer.Inner in = new Outer().new Inner();
in.function();
}
}
//编译失败 静态内部类知识点总结:
(1)、当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
(2)、在外部其他类中,如何直接访问静态内部类的非静态成员呢?
在主类主函数中{new Outer.Inner().function();}
(3)、在外部其他类中,如何直接访问静态内部类的静态成员呢?
在主类主函数中{new Outer.Inner.function();}
注意:当内部类中定义了静态成员,该内部类必须是static的。否则编译失败。
(4)、当外部类中的静态方法访问内部类是,内部类也必须是static的。
3、面向对象(内部类定义原则)
当描述事物时,事物内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。 例如这样:
class body
{
private class heart
{}
public void show()
{
new heart();
}
}
4、面向对象(匿名内部类)
Eg:
class Outer
{
int x = 3 ;
void method(final int a)
{
final int y = 4 ;
class Inner
{
void function()
{
System.out.println(a);
}
}
new Inner().function();
}
}
class InnerClassDemo
{
public static void main(String []args)
{
Outer out = new Outer();
out.method(7);
out.method(8);
}
}
内部类定义在局部时:
(1)、不可以被成员修饰符修饰。
(2)、可以直接访问外部类中的成员,因为还持有外部类中的引用,但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量。
匿名内部类:
(1)、匿名内部类,其实就是内部类的简写格式。
(2)、定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。
(3)、匿名内部类格式:new 父类或者接口(){定义子类的内容}
(4)、其实匿名内部类就是一个匿名子类对象,而且这个对象有点胖,可以理解为带内容的对象。
(5)、匿名内部类中定义的方法最好不要超过3个。
Eg(没匿名前)
abstract class AbsDemo
{
abstract void show();
}
class Outer
{
int x = 3 ;
class Inner extends AbsDemo
{
void show()
{
System.out.println("show:"+x);
}
}
public void function()
{
new Inner().show();
}
}
class InnerClassDemo
{
public static void main(String []args)
{
new Outer().function();
}
}
//输出结果:show:3
Eg2(有匿名后):
abstract class AbsDemo
{
abstract void show();
}
class Outer
{
int x = 3 ;
/*
class Inner extends AbsDemo
{
void show()
{
System.out.println("show:"+x);
}
}
*/
public void function()
{
//new Inner().show();
new AbsDemo()
{
void show()
{
System.out.println("show:"+x);
}
}.show(); //该部分就是注释掉部分的简写。
}
}
class InnerClassDemo
{
public static void main(String []args)
{
new Outer().function();
}
}
输出结果:show:3
//一道匿名内部类的练习。
interface Inter
{
void method();
}
class Test
{
//补足代码,通过匿名内部类
/*这注释部分是用来提示
* static class Inner implements Inter
* {
* public void method()
* {
* System.out.println("method run");
* }
* }
*/
//以下是补充的代码!
static Inter function() //静态的Inter类类型的function方法
{
return new Inter() //匿名内部类
{
public void method()
{
System.out.println("method run");
}
};
}
}
class InnerClassTest
{
public static void main(String[]args)
{
//由该段代码推断出以上需补足的代码!
Test.function().method();
}
}
上面代码我们这样入手:
(1)、Test.function():这段代码可以推断出Test类中有一个静态的方法function。
(2)、method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象。因为只有是Inter类型的对象,才可以调用method方法。
结合上面两点:
Test.function().method();
相当于
Inter in = Test.function();
in.method();
5、面向对象(异常概述)
异常:就是程序在运行时出现的不正常情况。
异常的由来:问题也是现实生活中一个现实的事物,也可以通过JAVA的类的形式进行描述,并封装成对象,其实就是JAVA对不正常情况进行描述后的对象体现。
对于问题的划分:两种,一种是严重的问题,一种是非严重的问题。
对于严重的问题:Java通过Error类来描述,而对于Error,一般不编写针对性代码对其进行处理。
对于非严重的问题:Java通过Exception类进行描述,这类可以使用针对性的处理方式进行处理。
无论Error或者Exception都具有一些共性的内容。比如:不正常情况的信息,引发的原因等。
体系:
Throwable
|--Error
|--Exception
6、面向对象(异常try-catch)
异常的处理: java提供了特有的语句进行处理:如下
try
{需要被检测的代码}
catch(异常类 变量)
{处理异常的代码:处理方式}
finally
{一定会执行的语句}
Eg:
class Demo
{
int div(int a, int b)
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String []args)
{
Demo d =new Demo();
try
{
int x = d.div(4, 0);//new ArithmeticException
System.out.println("x="+x);//没执行,而直接转到catch语句中去了
}
catch(Exception e)//相当于Exception e = new ArithmeticException();
{
System.out.println("除零啦"+"e:"+e.getMessage());//e: / by zero
e.printStackTrace();
}
System.out.println("over");//该句可以被执行到
}
}
程序结果:
除零啦e:/ by zero
java.lang.ArithmeticException: / by zero
at day09.Demo.div(Outer.java:7)
at day09.ExceptionDemo.main(Outer.java:18)
over
在程序中使用到的
-
getMessage()方法是Exception类继承父类Throwable类中方法,返回此 throwable 的详细消息字符串,即获取异常信息。
-
printStackTrace()方法是Exception类的方法,用来返回异常名称,异常信息和异常出现的位置。 其实JVM默认的异常处理机制,就是在调用printStaceTrace方法,打印异常的堆栈的跟踪信息。
7、面向对象(异常声明throws)
上一节的例子中应该要在Demo类中对div方法进行异常声明,如下,这样才不会引起程序崩溃。
class Demo
{
int div(int a, int b)throws Exception
/*
* throws Exception在功能上通过throws的关键字声明了该功能有可能会出现问题
* */
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String []args)
{
Demo d =new Demo();
try
{
int x = d.div(4, 0);//new ArithmeticException
System.out.println("x="+x);//没执行,而直接转到catch语句中去了
}
catch(Exception e)
{
System.out.println("除零啦"+"e:"+e.getMessage());//e: / by zero
e.printStackTrace();
}
System.out.println("over");//该句可以被执行到
}
}
8、面向对象(多异常处理)
(1)、在声明异常时,建议声明更为具体的异常,这样处理得更具体些。 例如在方法上进行具体的异常声明throws ArithmeticException后,我们在catch语句中就可以直接定义ArithmeticException异常类的对象进行处理,即catch(ArithmeticException e){处理语句}
(2)、对多异常处理的形式。在可能会出现多异常的方法上进行多异常声明:throws 异常1,异常2,......,然后在catch语句中需要分开进行处理,即
catch(异常1 e)
{处理语句}
catch(异常2 e)
{处理语句}
........
(3)、对方声明了多少个异常,就对应有多少个catch块,不要定义多余的,如果多个catch块中的异常出现继承关系,父类异常所对应的catch块要放在其他catch块的下面,或者最下面。
(4)、建议:在catch处理时,catch中一定要定义具体处理方式,不要简单定义一句e.printStackTrace(),也不要简单地就书写一条输出语句。一般可以把处理中的出错异常信息用日志文件记录。
9、面向对象(自定义异常)
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象,所以对于这些特有的问题可以按照java的对问题封装的思想,将特有的问题进行自定义的异常封装。
自定义异常:需求:在下面程序中,对于除数是-1,也视为是错误的,是用方法进行运算的,那么就需要对这个问题进行自定义描述。当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作,要么在内部try-catch处理,要么在函数上声明让调用者处理,一般情况下,函数内出现异常,函数上需要声明。
class FuShuException extends Exception
{
}
class Demo
{
int div(int a , int b )throws FuShuException
{
if(b<0)
{
throw new FuShuException(); //手动通过throw关键字抛出了一个自定义异常对象
}
return a/b;
}
}
class ExceptionDemo
{
public static void main(String []args)
{
Demo d = new Demo();
try
{
int x = d.div(4,-1);
System.out.println("x="+x);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("除数出现了负数了");
}
System.out.println("over");
}
}
输出结果:
day09.FuShuException
除数出现了负数了
over
发现打印的结果中只有异常的名称却没有异常的信息,因为自定义的异常并未定义信息。那么如何定义异常信息呢?观察一下代码:
class FuShuException extends Exception
{
private String msg;
FuShuException(String msg)
{
this.msg = msg;
}
public String getMessage()
{
return msg;
}
//继承父类Exception并重载了父类中的构造函数和getMessage方法。
}
class Demo
{
int div(int a , int b )throws FuShuException
{
if(b<0)
{
throw new FuShuException("出现了除数是负数的情况:/by fushu"); //继承类对父类构造函数进行了重载,因此我们可以在此处输入要定义的异常信息。
}
return a/b;
}
}
class ExceptionDemo
{
public static void main(String []args)
{
Demo d = new Demo();
try
{
int x = d.div(4,-1);
System.out.println("x="+x);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("除数出现了负数了");
}
System.out.println("over");
}
}
程序输出结果:
day09.FuShuException: 出现了除数是负数的情况:/by fushu
除数出现了负数了
over
但是由于在Java体系中存在这样一个父类:
class Throwable
{
private String message;
Throwable(String message)
{
this.message = message;
}
public String getMessage()
{
return message;
}
}
//而Exception又继承了Throwable类,因而有以下代码
class Exception extends Throwable
{
Exception(String message)
{
super(message);
}
}
因此,原来的代码中的class FuShuException extends Exception里的代码改为下面的
class FuShuException extends Exception
{
FuShuException(String msg)
{
super(msg);
}
}
因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时,通过super语句,将异常信息传递给父类,那么就可以直接通过getMessage方法获取自定义的异常信息。
自定义异常:必须是自定义类继承Exception类
继承Exception类的原因:异常体系有一个特点,因为异常类和异常对象都被抛出,他们都具有可抛性,这个可抛性是Throwable这个体系中独有的特点,只有这个体系中的类和对象才可以被throw和throws操作。
10、面向对象(throw和throws的区别)
throw和throws的区别:
(1)、throws使用在函数上,throw使用在函数内。
(2)、throws后面跟着异常类,可以很多个,用逗号隔开,throw后跟的是异常对象。
11、面向对象(RuntimeException)
Exception中有一个特殊的子类异常RuntimeException运行时异常如果在函数内抛出该异常,函数上可以不用声明,编译一样通过,如果在函数上声明了该异常,调用者可以不同处理编译一样可以通过。之所以不用在函数声明,是因为不需要让调用者处理,当该异常发生,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
自定义异常时,如果该异常发生了,无法再继续进行运算了,就让自定义异常继承RuntimeException。
对于异常分为两种:
(1)、编译时被检测到的异常。
(2)、编译时不被检测到的异常:RuntimeException和其子类。