接口:
当一个抽象类中全部是抽象方法的时候,这时,可以将这个抽象类定义成接口。
接口是一个特殊的抽象类。初期的一种简单理解。意味着接口中的方法都是抽象方法。
接口定义的格式:
interface 接口名{接口内容}
接口中的成员。都有固定修饰符。
常见:
1,常量。全局常量 有固定修饰符 public static final
2,抽象方法。固定修饰符public abstract
public static final int num=3;//=int num;
public abstract void show();//= void show();
接口定义特点:
1, 接口用interface来定义
2, 接口中的成员都有固定的修饰符。
3, 接口不能被实例化
4, 接口必须由其子类覆盖了所有的抽象发方法后,盖子类才可以实例化。否则该子类还是一个抽象类。
5, 接口中的成员都是public修饰的
接口的出现好处:
接口可以被多实现。是多继承在java种改良后的结果。
一个类可以实现多个接口。
误区:
记住:抽象函数,也要遵从函数的基本定义格式,要明确结果,要明确未知内容,只不过函数体由子类来完成。
一个类咋继承了一个类的同时还可以定义多个接口,接口的出现避免了单继承的局限新
class A
{
public void show(){}
}
interface B
{
public void show();
}
class C extends A implements B
{
//这里可以什么都不写,因为C先继承了A,它里面就有show()方法,可以用此来实
//现接口B中的show();
}
**类与类之间是继承关系,而且是单继承。
**类与接口之间是实现关系,而且可以多实现
**接口与接口之间是继承关系,而且可以多继承。
InterfaceDemoA
{
void showA();
}
InterfaceDemoB
{
void showB();
}
InterfaceDemoC extends DemoB,DemoA
{
void showC();
}
classDemoD implements DemoC
{
public void showA();
public void showB();
public void showC();
}
接口的特点
1, 接口是对外暴露的规则
2, 接口是程序的功能扩展
3, 接口的出现降低了耦合性
4, 接口可以用来多实现
接口和抽象类的区别:
1, 类是用来继承的,只能单继承
接口是用来实现的,可以多实现
2, 类中可以定义非抽象内容,直接提供给子类使用
接口中只能定义抽象方法,需要子类全部实现
3, 类存在着继承关系,是is a关系
接口的实现关系,是like a 关系
共同点:它们都是不断抽取而来的
没有抽象方法的抽象类
可以方便创建接口对象,去覆盖指定功能。
interface Inter
{
abstractvoid show1();
abstractvoid show2();
abstractvoid show3();
abstractvoid show4();
}
abstract Test implements Inter
{
publicvoid show1(){}
publicvoid show2(){}
publicvoid show3(){}
publicvoid show4(){}
}
class Test1 extends Test
{
publicvoid show1()
{
System.out.println("show1run");
}
}
class Test2 extends Test
{
publicvoid show2()
{
System.out.println("show2run");
}
}
多态:
在程序中的体现就是父类或者接口的引用只想自己的子类对象、
好处:提高代码的扩展性
弊端:前期建立父类的引用虽然可以接收后期所有该类的子类对象。但是只能使用父类中的功能,不能使用子类中的特有功能,因为前期的程序无法知道后期的子类特有的内容
但是前期的程序可以使用自雷覆盖了父类的方法的内容
前提:
1, 必须存在着继承关系
2, 通常要有覆盖操作
多态的出现在成员调用上的特点:
1, 成员变量
编译时期:参考的是引用型变量所属的类中是否有调用的成员变量,如果有,编译通过,如果没有编译失败
运行时期:调用的也是引用型变量所属类中的成员变量。
简单说:编译和运行都看等号的左边。
2, 成员函数
编译时期:参考的是引用型变量所属的类中是否有调用的方法。有,编译通过,没有编译失败。
运行时期:参考的是对象所属的类中是否有调用的方法,如果有运行子类自己的方法,如果没有就父类的方法
简单说:编译时期看左边,运行时期看右边。
因为函数有一个覆盖的特性
非静态方法需要和当期运行的对象进行动态绑定,哪个对象调用了这个方法,这个方法就所属于哪个对象。就会运行哪个对象中的方法
3, 静态函数
编译时期:参考的是引用型变量所属的类中的该方法。
运行时期:参考的也是引用型变量所属的类中的方法。
简单说:编译和运行都看左边
因为静态方法是不所属于对象的,是所属于类的,它会在类加载的时候,静态绑定到所属的类上
父类引用指向子类对象
a引用可以指向Animal类中的方法。
Animal a=newDog();//子类对象的类型提升。向上转型。
a.eat();
好处:提高了扩展性 局限:只能使用父类中的方法。
这种提升可以限制对子类对象的操作。
Dog d=(Dog)a;//向下转型,转成子类型
d.eat();
d.lookHome();
可以使用子类的特有方法。
弊端,如果类型转换错误,会出现运行异常。
什么时候使用向上转型,和向下转型?
* 当需要对程序进行扩展,或者限定对对象的方法操作时,使用向上转型。操作其父类型
* 当要使用子类的特有的内容时,就需要向下转型。转型前一定要判断,否则容易出现问题。
注意:在这个转型过程中,自始至终都是一个子类对象在做着类型的变化而已。千万别把父类对象转成子类型。那是不可能。
在进行子类特有方法使用时,要进行向下转型,转型前一定要做判断。否则容易发生
ClassCastException
判断引用类型,要使用一个关键字完成。关键字:instanceof
对象 instanceof 类型
这个判断是向下转型的健壮性判断
Object:
所有类型的父类。
所有对象都具备的内容不断的抽取,就到了一个顶层Object类中
----equals方法
其他某个对象是否与此对象相等,底层实在比较内存地址是否相同
class Person extends Object
{
Private int age;
Person(int age)
{
this.age=age;
}
//父类中已经提供了对象相等的比较,可以直接使用,如果比较内容不是所需要,可以将其覆盖,保留对其功能声明,定义自己所需的比较内容。
通常开发时,每一个对象都具备该方法,但是每个对象都具有自己的属性的比较方式。
所以都会覆盖方法建立每个对象自己特定的判断相同的依据。
publicboolean equals(Object obj)//Object obj=p2;Object obj=new Person(14);
{//只要年龄相同,就是同龄人,就是相同对象
//既然要用到对象的特有内容。先下转型。
if(!(obj instanceof Person))
return false;
Person p=(Person)obj;
return this.age==p.age;
}
}
class ObjectDemo
{
public static void main(String[] args)
{
Persond1=new Person();
Persond2=new Person();
booleanb=d1.equals(d2);
System.out.println("b="+b);
}
}
----toString() 返回对象的字符串表达式
如果输出语句中直接输出一个引用型变量,它会自动调用该对象toString变成字 符串打印
为了让自定义的对象对应的字符串表现形式有意义,可以覆盖toString方法
内部类
特点:内部类可以直接访问外部类中的成员
外部类要访问内部类中的成员,必须要创建内部类的对象。
当内部类编译后,其class文件是有所属关系的
Outer$Inner.class
class Outer
{
classInner
{
publicvoid method()
{
System.out.println("methodrun="+num);
}
}
intnum=7;
publicvoid show()
{
Innerin=new Inner();
in.method();
}
}
为什么要定义内部类?
类是用于描述事物的,而事物中如果还有具体的事物,而且这个内部的事物在访问着所属事物中的内容,这时这个内部的事物,也需要用到类来描述。这个类就是内部类。
为什么内部类可以直接访问外部类中的成员呢?
因为内部类都持有一个外部类的引用。外部类名.this
内部类的修饰符
当内部类定义在外部类的成员位置上时,可以使用成员的修饰符来进行内部类的修饰
1, 权限修饰符
默认或者公有
可以直接这样访问内部类
外部类名.内部类名变量名=new 外部类对象.new 内部类对象;
Outer.Inner in = new Outer().new Inner();
私有:是不可以直接在外部访问。
2,static修饰符
内部类被静态修饰,出现访问局限性,只能访问外部类中的静态成员
内部类被静态后,会随着外部类的加载而加载。
如果内部类中定义了静态成员,该内部类必须被静态修饰
访问静态内部类中的非静态成员。直接穿件内部类对象。
外部类名.内部类名 变量名=new 外部类名.内部类名
Outer.Inner in=new Outer.Inner();
访问静态内部类中的静态成员。不需要对象。
外部类名.内部类名.内部类的静态成员
Outer.Inner.function();
记住:内部类只有定义在外部类的成员位置上,才具备这些修饰符、
匿名内部类
凡是匿名都是简写格式
要定义匿名内部类,必须要前提
前提:内部类需要继承或者实现一个外部的类或者接口,这时才能简写成匿名内部类的形式
匿名内部类其实就是一个匿名子类对象。这个对象用{}结尾部定义了成员。也就是说是
一个带有成员内容的对象,这个对象有点胖。
格式:new 父类名或接口名().成员。
abstract classDemo
{
abstract void show();
}
class Outer
{
private int num=5;
public void method()
{
Demo d=new Demo()
{
void show()
{
System.out.println(“show run…….”+num);
}
};
d.show();
}
}
匿名内部类使用场景之一:
当接口类型参数,该接口中方法不超过3个,可以使用匿名内部类作为函数的参数进行传递,这样简化了书写。但是接口方法较多时,不要使用匿名内部类,影响阅读性。
异常
在运行时期发生的一些不正常情况。
异常的由来:程序运行时总会有些不正常的情况。Java语言对这些不正常情况也进行了描述。并对这些不正常进行了对象的封装。是描述不正常情况的对象
异常体系:
Throwable:可抛出
|——Error:严重问题。一般都是jvm从底层抛出来的问题,通常不需处理。
|——Exception:可以定义针对性的处理方式对该种情况进行处理
不正常情况分为两种:一种是可以解决的Exception,一种是严重性的Error
无论是Error还是Exception,它们的子类都有一个特点:子类名称的后缀都是父类名
这个异常体系最大的特点:就在于体系中的类和对象都具备可抛性。可抛性的体现就是无论是类,还是对象都可以被throws或者throw所操作。throws操作类,throw操作对象
处理方式:
1, 声明抛出。告诉调用者功能会有问题。通过throws关键字对问题声明在功能上。
2, 进行捕捉。可以使用针对性的捕捉代码块完成
try
{
//需要被检测的代码;
}
catch(异常类 变量)//该变量用于接收try检测到的异常对象
{
//异常处理代码
}
finally
{
//一定会被执行的代码
//主要用于释放资源,无论是否发生异常,有些动作一定要执行,那么这些动、、//作定义在finally代码块中
}
throws throw关键字有什么区别?
throws用在函数上,用于功能声明异常,后面抛出的是异常类可以抛出多个,只要用于逗号隔开即可。
throw只能用于在函数内,用于抛出异常对象,额外特点,一旦执行,就可以结束功能。
自定义异常:
对于常见的不正常情况,java都有对应的描述,比如角标越界,或者空指针等。
对于自定义的程序中的出项的特有问题,java并没有给出对应的描述
这时就需要我们按照面向对象的思想对这个问题进行描述,像异常一样将其封装成对象
定义的方式:
1, 定义一个类,对问题进行描述。
2, 必须要让这个类继承异常类,具备可抛性
细节:
1,定义功能,功能内部因为传入的参数问题,导致了功能会出现问题,这时为了解决这个问题,通常,我们都会将问题通过throws声明在函数上。
目的:为了调用者在使用这个功能的时候,能明确处理方式,也就是说throws抛出的目的是为了让调用者预先定义好问题的处理方式。
2,如果一个功能抛出多个异常。
那么在调用该功能时,需要有多个catch进行每一个异常的指针处理,如果多个catch中有父类异常,一定要定义在最下面,否则编译失败。
3, 特殊部分:
函数内throw抛出异常对象,函数上一定要用throws声明,否则编译失败,调用到声明异常的函数,要进行throws声明抛出,或者try catch捕捉,否则,编译失败。
注意:异常分两种
1, 编译是被编译器检测的异常。
2, 编译时不被检测的异常。这种异常出现,编译时期是不在检查之列。这种异常称为运行时异常。也就是说函数内throw抛出运行时异常,不需要在函数上声明,即使声明了。调用者也不用一定给出预先处理方式,因为它不会导致编译失败
通常,不编写针对性的代码进行处理。一旦发生,就让程序停掉。为了对待吗进行修正。
区分方式:
Exception中的一个特殊子类:RuntimeException就是运行时异常。
RuntimeException和其他子类都不需要编译时检测
意味着:我们在自定义异常时,可以继承Exception,称为编译时被检测
的异常。也可以继承RuntimeException,称为运行时异常
在进行异常捕捉时,代码快的不同组合情况
1,try catch finally
2,try catch//没有需要一定被执行的代码-不需要资源的动作。
3,try finally。异常并没有被处理,但是却涉及到了资源的调用,资源需要被关
闭,所以就有了,将异常进行对外声明,因为没有catch,但是资源是在功能内部打开的,必须要功能内部关闭。就有了try和finally的组合。
数据库中组合的模型
try
{
//1,连接数据库
//2,存储数据,存储失败,会发生异常
}
catch(数据库异常 e)
{
//异常处理代码
}
finally
{
//3,关闭数据库连接,连接必须关闭,因为要释放资源
}
异常覆盖中的细节:
1,子类在覆盖父类时,如果父类中被覆盖的方法抛出了异常,
那么子类覆盖的方法只能抛出相同异常,或该异常的子类异常
2,如果父类的覆盖方法抛出了多个异常,子类在覆盖时,只能抛出这些异常的子集
3,如果被覆盖的方法没有抛出异常,子类也不允许抛出异常。如果子类中真的出现异常,只能在子类方法内进行try处理,绝对不允许throws声明,万一处理不了,可以抛出运行时异常