Java学习笔记(10)
目前多态情况下不能访问子类特有的成员
如果需要访问子类特有的成员,那么需要进行类型强制转换,转换为子类的类型然后再进行调用
基本数据类型的转换:
小数据类型-------------》大数据类型 不会报错 自动类型转换
大数据类型-------------》小数据类型 可能会损失精度 (强制类型转换) 小数据类型 变量名=(小数据类型) 大数据类型
引用数据类型之间的转换:
小数据类型-------------》大数据类型 不会报错 自动类型转换
大数据类型-------------》小数据类型 强制类型转换
类型转换最常见的问题:java.lang.ClassCastException 强制类型转换失败
实现关系下的多态:
接口 变量=new 接口实现类的对象
public class Demo2 { public static void main(String[] args) {
// TODO Auto-generated method stub
//实现关系下的多态
Dao d=new UserDao();
d.add();
} }
interface Dao{
public void add();
public void delete();
} class UserDao implements Dao{
public void add() {
System.out.println("添加元素成功!");
}
public void delete() {
System.out.println("删除元素成功!");
}
}
结果为:添加元素成功!
对于这种多态,只会调用实现类的方法,因为接口中的方法都是抽象的,所以都是非静态的,所以永远都是调用子类的方法,即为实现类的方法
内部类:一个类定义在另外一个类的内部,那么该类就称作为内部类
内部类的class文件名:外部类$内部类.class
好处:便于区分该class文件是属于哪个外部类的
内部类的类别:
- 成员内部类
- 局部内部类
成员内部类的访问方式:
1.在外部类提供一个方法创建内部类的对象进行访问
public class InnerClass { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer outer=new Outer();
outer.instance();
} }
class Outer {
int x=100; //成员变量
class Inner { //内部类与成员变量可以看作是一个等级的
int i=10;
public void print() {
System.out.println("这个是成员内部类的print方法!");
}
}
//在外部类的方法中创建了内部类的对象,然后调用内部方法
public void instance() {
Inner inner=new Inner();
inner.print();
}
}
2.在其他类直接创建内部类的对象 格式:外部类.内部类 变量名=new 外部类().new 内部类();
注意:如果是一个静态内部类,那么在其他类创建的格式: 外部类.内部类 变量名=new.外部类().内部类;
public static void main(String[] args) {
// TODO Auto-generated method stub
//Outer outer=new Outer();
//outer.instance();
Outer.Inner inner=new Outer().new Inner();
inner.print();
}
内部类的好处:内部类可以直接访问外部类的所有成员
内部类的应用场景:我们在描述事物A的时候,发现描述的A事物内部还存在另外一个比较复杂的事物B的时候,而且这个比较复杂的事物B还需要访问A事物的属性等数据,那么这时候我们就可以使用内部类描述B事物
内部类要注意的细节:
- 如果外部类与内部类存在同名的成员变量时,在内部类中默认情况下是访问内部类的成员变量。可以通过外部类.this.成员变量名指定访问外部类的成员。
- 私有的成员内部类只能在外部类提供一个方法创建内部类的对象进行访问,不能在其他类创建对象了
- 成员内部类一旦出现了静态的成员,那么该类也必须使用static修饰
class Outer {
int x=100; //成员变量
class Inner { //内部类与成员变量可以看作是一个等级的
int x=200;
int i=10;
public void print() {
System.out.println("这个是成员内部类的print方法!");
System.out.println("x=:"+x);
}
} 结果:这个是成员内部类的print方法!
x=:200
class Outer {
int x=100; //成员变量
class Inner { //内部类与成员变量可以看作是一个等级的
int x=200;
int i=10;
public void print() {
System.out.println("这个是成员内部类的print方法!");
System.out.println("x=:"+Outer.this.x);
}
} 结果:这个是成员内部类的print方法!
x=:100
3.
public class InnerClass { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer outer=new Outer();
outer.instance();
//Outer.Inner inner=new Outer().new Inner();
//inner.print()
System.out.println(Outer.Inner.a);
} }
class Outer {
int x=100; //成员变量
static class Inner { //内部类与成员变量可以看作是一个等级的
int x=200;
int i=10;
static int a=10;
public void print() {
System.out.println("这个是成员内部类的print方法!");
System.out.println("a=:"+a);
}
}
public void instance() {
Inner inner=new Inner();
inner.print();
}
结果:
这个是成员内部类的print方法!
a=:10
10
如果是静态内部类,那么以前的创建对象的格式就错误了(Outer.Inner inner=new Outer().new Inner();)
现在应该是以下这样:
Outer.Inner inner=new Outer.Inner();
inner.print();
局部内部类:那么另外一个类就称作为局部内部类
定义:
public class LocalInnerClass { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer1 outer=new Outer1();
outer.test();
} }
class Outer1{
public void test() {
int y=10; //局部变量
class Inner1{
int x=10;
public void print() {
System.out.println("这个是局部内部类的print方法!");
}
}
Inner1 inner=new Inner1();
inner.print();
}
}
局部内部类要注意的细节:
- 如果局部内部类访问了一个局部变量,那么该局部变量必须使用final修饰 解决方案:如果一个局部内部类访问一个局部变量的时候,那么就让该局部内部类访问这个局部变量的复制品。
匿名内部类:没有类名的类就称作为匿名内部类
匿名内部类的好处:简化书写
匿名内部类的使用前提:必须存在继承或者实现关系才能使用
例:
局部内部类做法:
public class Anonymous { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer3 outer=new Outer3();
outer.print();
} }
abstract class Animal2{
public abstract void run();
}
class Outer3{
public void print() {
//需求:在方法体内部定义一个类继承Animal类,然后调用run方法
class Dogs extends Animal2{
public void run() {
System.out.println("狗在跑!");
}
}
//创建对象
Dogs d=new Dogs();
d.run();
}
} 结果:狗在跑!
匿名内部类只是没有类名,其他的一概成员都是具备的。
public class Anonymous { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer3 outer=new Outer3();
outer.print();
} }
abstract class Animal2{
public abstract void run();
}
class Outer3{
public void print() {
//需求:在方法体内部定义一个类继承Animal类,然后调用run方法
//匿名内部类
new Animal2(){
//匿名内部类的成员
public void run() {
System.out.println("狗在跑!");
}
}.run();
} } 结果:狗在跑!
对于以上代码:
- 匿名内部类与Animal2是继承的关系
- 目前这个new不是创建Animal的对象,而是创建Animal子类的对象,只是借用了父类的名字
- 匿名内部类也可以有自己特有的方法
new Animal2(){
//匿名内部类的成员
public void run() {
System.out.println("狗在跑!");
}
public void bite() {
System.out.println("狗在咬人!");
}
}.bite(); 结果:狗在咬人!
当需要调用的函数为多个时,可以将某个函数的返回值类型void改为父类类型,然后再用this指代,具体如下:(其中注释的代码中有局部内部类对此问题的解决方法)
public class Anonymous { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer3 outer=new Outer3();
outer.print();
} }
abstract class Animal2{
public abstract Animal2 run();
public abstract void sleep();
}
class Outer3{
public void print() {
//需求:在方法体内部定义一个类继承Animal类,然后调用run方法和sleep方法
/*class Dogs extends Animal2{
public void run() {
System.out.println("狗在跑!");
}
public void sleep() {
System.out.println("狗趴着睡觉!");
}
}
//创建对象
Dogs d=new Dogs();
d.run();
d.sleep();
*/
//匿名内部类
new Animal2(){
//匿名内部类的成员
public Animal2 run() {
System.out.println("狗在跑!");
return this;
}
public void sleep() {
System.out.println("狗趴着睡觉!");
}
public void bite() {
System.out.println("狗在咬人!");
}
}.run().sleep();;
}
} 结果为:狗在跑!
狗趴着睡觉!
当然,局部内部类中也可以使用如上所述方法,使得run返回this,由于返回值也不会去调用,但也可以输出结果
class Dogs extends Animal2{
public Animal2 run() {
System.out.println("狗在跑!");
return this;
}
public void sleep() {
System.out.println("狗趴着睡觉!");
}
}
//创建对象
Dogs d=new Dogs();
d.run();
d.sleep(); 结果:狗在跑!
狗趴着睡觉!
除了上述想法,我们也可以联想到,可以用一个变量来承接这个匿名类,使得我们也可以使用a.函数名()调用方法了1,那么这个变量是什么类型呢,我们可以想到Animal类型,那么此时我们就使用多态了。
Animal2 a=new Animal2(){ //多态的使用 Animal a=new 子类();
//匿名内部类的成员
public void run() {
System.out.println("狗在跑!");
//return this;
}
public void sleep() {
System.out.println("狗趴着睡觉!");
}
public void bite() {
System.out.println("狗在咬人!");
}
};
a.run();
a.sleep(); 结果:狗在跑!
狗趴着睡觉!
//我现在把上面的代码修改回去了,run函数依旧是void类型,但其实不修改也可以,因为即使return this了之后,返回值也不会被使用,思路和上面局部内部类的的类似
实现关系下的匿名内部类:
public class Anonymous { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer outer=new Outer();
outer.print();
} }
interface Dao{
public void add();
}
class Outer{
public void print() {
//创建一个匿名内部类的对象
new Dao() { //接口并不能创建对象,这里是接口的实现类的对象,只是借用了接口的名字而已
public void add() {
System.out.println("添加成功!");
}
}.add();;
}
} 结果:添加成功!
匿名内部类一般是用于实参。
public class Anonymous { public static void main(String[] args) {
// TODO Auto-generated method stub
Outer outer=new Outer();
outer.print();
test(new Dao() {
public void add() {
System.out.println("添加员工成功!");
}
});
}
public static void test(Dao d) {//这里需要传接口的实现类,因为接口本身不能创建对象
d.add();
} }
interface Dao{
public void add();
} 结果:添加成功!
添加员工成功!
以后基本接触到的都是作为实参使用。
异常:我们的Java程序也是会存在某些不正常的情况的,这些不正常的情况我们就统称为异常
在Java程序中也会出现程序不正常的情况,Java是面向对象的语言,任何的事物都可以使用类进行描述,那么这时候sun就使用了很多的类描述了Java程序中各种不正常的情况,而用于描述程序不正常的情况的类我们称作为异常类,很多异常堆积起来,就形成了java中的异常体系
异常体系
————————| Throwable (所有异常或者错误类的超类)
————————————| Error (错误)错误一般是由于jvm或者是硬件引发的问题,所以我们一般不会通过代码去处理错误的。
————————————| Exception (异常) 是需要通过代码区处理的
Throwable类:常用的方法
- toString() 返回此throwable的简短描述 返回当前异常对象的完整类名+病态信息 包名+类名=完整类名
- getMessage() 返回的是创建Throwable传入的字符串信息
- printStackTrace() 打印异常的栈信息 (因为异常就像是栈底的异常引起上面的异常,一个个累积,相当于进栈)
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建了一个Throwable对象
Throwable t=new Throwable();
String info=t.toString();
System.out.println("toString: "+info); //java.lang.Throwable 包名+类名=完整类名
} 结果:toString: java.lang.Throwable
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建了一个Throwable对象
Throwable t=new Throwable();
String info=t.toString();
String message=t.getMessage();
System.out.println("toString: "+info); //java.lang.Throwable 包名+类名=完整类名
System.out.println("message:"+message);
} 结果:toString: java.lang.Throwable
message:null //创建对象时括号中的就是病态信息
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建了一个Throwable对象
Throwable t=new Throwable("头晕,感冒");
String info=t.toString();
String message=t.getMessage();
System.out.println("toString: "+info); //java.lang.Throwable 包名+类名=完整类名
System.out.println("message:"+message);
} 结果:toString: java.lang.Throwable: 头晕,感冒
message:头晕,感冒
public class Exception { public static void main(String[] args) {
// TODO Auto-generated method stub
//创建了一个Throwable对象
/*Throwable t=new Throwable("头晕,感冒");
String info=t.toString();
String message=t.getMessage();
System.out.println("toString: "+info); //java.lang.Throwable 包名+类名=完整类名
System.out.println("message:"+message);
*/
test();
}
public static void test() {
Throwable throwable=new Throwable();
throwable.printStackTrace();
}
} 结果:
java.lang.Throwable
at test3.Exception.test(Exception.java:17)
at test3.Exception.main(Exception.java:14)
jvm在默认情况下只能管理64M内存
Error : 错误一般是由于jvm或者是硬件引发的问题,所以我们一般不会通过代码去处理错误的。
public static void main(String[] args) {
// TODO Auto-generated method stub
//jvm在默认情况下只能管理64M内存
byte[] buf=new byte[1024*1024*1024];
}
这个会产生内存超出的错误
Exception:是需要通过代码去处理的
如何区分代码与异常呢:
如果程序出现了不正常的信息,如果不正常的信息的类名是以Error结尾的,那么肯定是一个错误。
如果是以Exception结尾的,那么肯定就是一个异常
public class Error { public static void main(String[] args) {
// TODO Auto-generated method stub
//jvm在默认情况下只能管理64M内存
//byte[] buf=new byte[1024*1024*1024];
div(4,0);
}
public static void div(int a,int b) {
int c=a/b;
System.out.println("c="+c);
} } 结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at test3.Error.div(Error.java:12)
at test3.Error.main(Error.java:9)
上面的结果是通过printStackTrace方法打印出来,那么异常对象从何而来呢?
答: jvm运行到a/b这个语句时,发现b为0,除数为0在我们现实生活中是属于不正常的情况,jvm一旦发现了这种不正常的情况时候,那么jvm就会马上创建一个对应的异常对象,并且会调用这个异常对象的printStackTrace的方法来处理
一般的异常运行到的时候就不会执行后面的语句了,所以为了让后面的执行,需要处理异常
异常的处理:
方式一:捕获处理
捕获处理的格式:
try{
可能发生异常的代码
}catch(捕获的异常类型 变量名){
处理异常的代码。。。
}
public class Error { public static void main(String[] args) {
// TODO Auto-generated method stub
//jvm在默认情况下只能管理64M内存
//byte[] buf=new byte[1024*1024*1024];
div(4,0);
}
public static void div(int a,int b) {
int c=0;
try {
c=a/b; //jvm在这句话的时候发现了不正常的情况,那么就会创建一个对应的异常对象
}catch(ArithmeticException e) { //捕获异常类型
//处理异常的方法
System.out.println("toString:"+e.toString());
}
System.out.println("c="+c);
} } 结果:
toString:java.lang.ArithmeticException: / by zero
c=0
这时候就会输出c了
捕获处理要注意的细节:
- 如果try块中的代码出现了异常经过了处理之后,那么try-catch块外面的代码可以正常的执行
- 如果try块中出现了异常的代码,那么在try块中出现异常代码后面的代码是不会执行了
- 一个try块后面是可以跟有多个catch块的,也就是一个try块可以捕获多种异常的类型
- 一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获,否则编译报错 (比如捕获Exception 类型就得放在最下面的catch,因为其是所有异常类型的父类,否则就让其他代码都是废话了,编译就会报错)
public class Error { public static void main(String[] args) {
// TODO Auto-generated method stub
//jvm在默认情况下只能管理64M内存
//byte[] buf=new byte[1024*1024*1024];
int[] arr=null;
div(4,2,arr);
}
public static void div(int a,int b,int[] arr) {
int c=0;
try {
c=a/b; //jvm在这句话的时候发现了不正常的情况,那么就会创建一个对应的异常对象
System.out.println("数组的长度:"+arr.length);
}catch(ArithmeticException e) { //捕获异常类型
//处理异常的方法
System.out.println("toString:"+e.toString());
}catch(NullPointerException e) {
System.out.println("出现了空指针异常");
}
System.out.println("c="+c);
} } 结果:
出现了空指针异常
c=2
方式二:抛出处理
throw
throws
抛出处理要注意的细节:
- 如果一个方法的内部抛出了一个编译时异常对象,那么必须要在方法上声明抛出
- 如果调用了一个声明抛出编译时异常的方法,那么调用者必须要处理异常
- 如果一个方法内部抛出了一个异常对象,那么throw语句后面的代码都不会再执行了(一个方法遇到了throw关键字,该方法也会马上停止执行的)
- 在一种情况下,只能抛出一种类型的异常
public class Test { public static void main(String[] args) {
// TODO Auto-generated method stub
try {
div(4,0); //此方法调用了一个抛出异常的方法,所以它就必须要处理这个异常,所以用try-catch方法
}catch(Exception e) {
System.out.println("出现异常了...");
e.printStackTrace();
}
}
public static void div(int a,int b) throws Exception{ //声明抛出
if (b==0) {
throw new Exception();
}
int c=a/b;
System.out.println("c="+c);
}
} 结果:
出现异常了...
java.lang.Exception
at test.Test.div(Test.java:16)
at test.Test.main(Test.java:8)
当然也可以在div函数再次抛出
public class Test { public static void main(String[] args) throws Exception{ //如果这样抛出异常,那么这时候调用者就是main也就是jvm,所以jvm会打印异常信息
// TODO Auto-generated method stub
//try {
div(4,0); //此方法调用了一个抛出异常的方法,所以它就必须要处理这个异常,所以用try-catch方法
/*}catch(Exception e) {
System.out.println("出现异常了...");
e.printStackTrace();
}*/
}
public static void div(int a,int b) throws Exception{
if (b==0) {
throw new Exception();
}
int c=a/b;
System.out.println("c="+c);
}
} 结果:
Exception in thread "main" java.lang.Exception
at test.Test.div(Test.java:16)
at test.Test.main(Test.java:8)
以下为需要注意的第四点的代码 public static void main(String[] args){ //如果这样抛出异常,那么这时候调用者就是main也就是jvm,所以jvm会打印异常信息
// TODO Auto-generated method stub
try {
int[] arr=null;
div(4,2,arr); //此方法调用了一个抛出异常的方法,所以它就必须要处理这个异常,所以用try-catch方法
}catch(Exception e) {
System.out.println("出现异常了...");
e.printStackTrace();
}
}
public static void div(int a,int b,int[] arr) throws Exception,NullPointerException{
if (b==0) {
throw new Exception();
}
else if (arr==null){
throw new NullPointerException();
}
int c=a/b;
System.out.println("c="+c);
} 结果:
出现异常了...
java.lang.NullPointerException
at test.Test.div(Test.java:20)
at test.Test.main(Test.java:9)
throw与throws两个关键字:
- throw关键字是用于方法内部的,throws是用于方法声明上的
- throw关键字是用于方法内部抛出一个异常对象的,throws关键字是用于在方法声明上声明抛出异常类型的
- throw关键字后面只能有一个异常对象,throws后面一次可以声明抛出多种类型的异常
何时使用抛出处理
如果你需要通知到调用者,你的代码出了问题,那么这时候就使用抛出处理
如果代码是直接与用户打交道,遇到了异常千万不要再抛,再抛的话,就给了用户了,这时候就应该使用捕获处理。
Java学习笔记(10)的更多相关文章
- Java 学习笔记(10)——容器
之前学习了java中从语法到常用类的部分.在编程中有这样一类需求,就是要保存批量的相同数据类型.针对这种需求一般都是使用容器来存储.之前说过Java中的数组,但是数组不能改变长度.Java中提供了另一 ...
- Java学习笔记10
31.编写当年龄age大于13且小于18时结果为true的布尔表达式age > 13 && age < 18 32.编写当体重weight大于50或身高大于160时结果为t ...
- java学习笔记(10) —— ActionContext、ServletActionContext、ServletRequestAware用法
核心思想 1.ActionContext HttpServletRequest getAttribute setAttribute ActionContext get put //ActionCont ...
- Java学习笔记10(面向对象三:接口)
接口: 暂时可以理解为是一种特殊的抽象类 接口是功能的集合,可以看作是一种数据类型,是比抽象类更抽象的"类" 接口只描述所应该具备的方法,并没有具体实现,具体实现由接口的实现类(相 ...
- Java学习笔记-10.io流
1.输入流,只能从中读取数据,而不能向其写出数据.输出流,只能想起写入字节数据,而不能从中读取. 2.InputStream的类型有: ByteArrayInputStream 包含一个内存缓冲区,字 ...
- Java学习笔记10(面对对象:构造方法)
在开发中经常需要在创建初始化对象时候明确对象的属性值, 比如Person对象创建的时候就给Person的属性name,age赋值, 这里就要用到构造方法: 构造方法是类的一种特殊方法,它的特殊性体现在 ...
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
- Java学习笔记(04)
Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
随机推荐
- hdu 1162 Eddy's picture(最小生成树算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1162 Eddy's picture Time Limit: 2000/1000 MS (Java/Ot ...
- 【自己练习】linux常见命令——(六)
菜鸟教程命令大全 http://www.runoob.com/linux/linux-command-manual.html 命令大全: http://man.linuxde.net/ ta ...
- Python3 面向对象编程高级语法
1.静态方法: #!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:CarsonLi class Dog(object): def __init ...
- 利用eclipse调试ofbiz之debug使用
1.项目右键-配置debug 2.new一个debug调试 3.配置运行类org.ofbiz.base.start.Start 4.设置内存大小:arguments-VM arguments -Xms ...
- SQL语句获取时间的方法
1. 当前系统日期.时间select getdate() 2. dateadd 在向指定日期加上一段时间的基础上,返回新的 datetime 值例如:向日期加上2天select dateadd(day ...
- debian下没有公钥解决办法
debian下没有公钥解决办法 执行命令:apt-get update 出现如下错误 正在读取软件包列表... 完成 W: 以下 ID 的密钥没有可用的公钥: 8B48AD6246925 ...
- django的事务
在某些时候,你可能会在视图修改两张数据表.并且想让他们同时成功或者同时失败.这就是事务的原子性(atomicity).在django中应该怎么做呢? 详细可以参考官方文档:https://yiyibo ...
- HDU-5335
Walk Out Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Su ...
- LightOJ 1282
Leading and Trailing Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %lld & %llu S ...
- 在k8s中安装flannel的故障解决: Failed to create SubnetManager: error retrieving pod spec for : the server does not allow access to the requested resource
花了一个上午来追踪问题,k8s都反复新建了十多次,docker都重启了几次.(一次显示不有获取磁盘空间,重启docker,清空存储解决) 在用kubeadm安装容器化的几个组件时,flannel组件死 ...