1.抽象类:
1.抽象类的概念:
在面向对象的概念中,所有对象都是通过类来描绘的,但是反过来,并不是所有类都可以用来描绘对象的,如果一个类中没有足够的信息来描绘一个具体的对象时,这个类就叫做抽象类。
1.Animal是动物类,但是每个动物都有不同的叫声,但是Animal不是具体的动物,所以Animal里面的bark方法无法具体实现
2.Dog类是狗类,狗是一个具体的动物,所以Dog与Animal是继承关系,又因为狗是具体的动物,所以Dog的bark()方法是可以实现的
3.Cat类是猫类,猫是一个具体的动物,所以猫与Animal也是继承关系,又因为猫是具体的动物,所以Cat的bark()方法是可以实现的
4.因此,Animal类可以设置成抽象类
2.抽象类的语法:
在java中,一个类被abstract修饰,那它就是抽象类,如果一个方法被abstract修饰,那它就是抽象方法,在抽象方法中,不用给出具体的实现方法
public abstract class Animal{
public abstract void bark();//被abstract修饰的方法是抽象方法,没有方法体
//抽象类也是类,也可以有普通方法和成员变量
public String name;
public String Getname(){//普通方法
return this.name;
}
}
注意:抽象类也是类,内部也可以包含普通方法和属性,甚至是构造方法。
抽象类和普通类的区别是:抽象类中可以包含抽象方法。
3.抽象类的特性:
注意:抽象方法的出现就是用来继承的。
1.抽象类是不能直接实例化对象的
2.抽象方法是不能用private进行修饰的
3.抽象方法是不能用static和final修饰的,因为子类要重写抽象方法
4.抽象类必须被继承,而且子类必须重写抽象类中的抽象方法,否则子类也必须是抽象类,必须要使用abstract修饰。
5.抽象类中不一定包含抽象方法,但有抽象方法的类一定是抽象类。
6.抽象类中也可以有构造方法,在子类创建对象时,初始化父类的成员变量。
4.抽象类的作用:
1.抽象类本身不能被实例化,只能用子类对抽象类进行继承同时对抽象类的抽象方法进行重写
2.普通类也可以被继承,普通方法也能被重写,为什么一定要抽象类和抽象方法?
因为有些语法存在是为了“预防出错”,充分利用编译器的校验, 在实际开发中是非常有意义的.
2.接口:
在现实生活中,接口的例子有很多,比如下面这个插座,可以插吹风机和电脑等等
还有笔记本电脑上的USB插口等等。
电脑的USB口上,可以插:U盘、鼠标、键盘...所有符合USB协议的设备
电源插座插孔上,可以插:电脑、电视机、电饭煲...所有符合规范的设备
接口的特性与语法规则:
public interface 接口名称{
public abstract void method1();//public abstract是固定搭配,可以省略不写
public void method2();
abtract void method3();
void method4();
}
以上的写法在接口内都是抽象方法(接口和抽象类有一些相似),推荐像method4这样写。
接口的使用:
接口不能直接使用,必须有一个实现类来实现该接口,并且实现接口中的抽象方法。
public class 类名称 implement 接口名称{
........
}
子类和父类之间是通过extends继承关系,类与接口之间通过implements来实现关系的
public interface 接口1 {
void test1();
void test2();
}
public class 类1 implements 接口1{
//实现接口中的抽象方法
@Override
public void test1() {
System.out.println("test1...");
}
@Override
public void test2() {
System.out.println("test2...");
}
}
在实现了接口的类中,要将接口内的抽象方法进行重写。
但是如果这个类不想实现接口中的抽象方法,那么这个类就要定义为抽象类。如果这个抽象类被继承,那么子类就要实现所有没有实现的方法
接口的特性:
1.接口中的成员变量,默认由public static final 修饰的
public interface 接口名称 {
int a=10;
public static final aa=10;
}
所以接口的成员变量是不依赖对象(但是接口不能实例化对象),且为常量(不能被修改)
2.接口当中的抽象方法,都是默认由public abstract修饰的。
public interface 接口名称{
public abstract void method1();
void method2();
}
method1()方法和method2()方法只是写法上的不同,效果都一样,同时可以省略public abstract
注意:接口中的抽象方法不能在接口内实现,必须要由实现接口的类来实现,也就是要在类中重写接口中的抽象方法
3.如果接口当中的方法被default修饰,那就可以有具体实现
public interface 接口名称 {
default void test(){
System.out.println("test....");
}
}
4.如果接口中的方法被static修饰,那也可以有具体的实现:
public interface 接口名称 {
static void test(){
System.out.println("test....");
}
}
然后在实现接口的类中,可以调用此方法。
5.接口是不能进行实例化的。
6.重写接口中的抽象方法时,不能使用默认的访问权限(default)
因为接口中的抽象方法默认是public abstract,所以实现接口的类重写的方法的访问权限也要大于等于接口中的抽象方法的访问权限
7.接口中不能有静态代码块,实例代码块和构造方法
8. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
9. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
10. jdk8中:接口中还可以包含default方法。
3.实现多个接口:
在java中,类与类之间只能存在单继承,就是一个类只能继承一个类,java中不支持多继承,但是一个类可以实现多个接口。下面通过代码来解释:
定义一个Animal类:
public class Animal {
public String name;//动物的名称
public Animal(String name){//构造方法
this.name=name;
}
}
再实现多个接口,“会游泳的”,“会飞的”,“会跑步的”。
public interface Iswimming {//会游泳的
void swim();
}
public interface Irunning{//会跑的
void run();
}
public interface Iflying{//会飞的
void fly();
}
接下来我们创建几个具体的动物的类。
比如:猫是会跑的,猫也是动物,需要继承Animal类,然后实现“会跑的”接口
public class Cat extends Animal implement Irunning{
public Cat(String name){//初始化name
super(name);
}
//重写接口中的抽象方法
public void Irunning(){
System.out.println(this.name+"正在跑步");
}
}
这是猫类,但还有一种动物,鸭子,既能游泳,又能跑步,又能飞。
public class Duck extends Animal implement Iswimming,Irunning,Iflying {
public Duck(String name){//初始化name
super(name);
}
//重写接口中的抽象方法
public void Irunning(){
System.out.println(this.name+"正在跑步");
}
public void Iswimming(){
System.out.println(this.name+"正在游泳");
}
public void Iflying(){
System.out.println(this.name+"正在飞");
}
}
4.内部类:
内部类是定义在另一个类中的类,那为什么需要使用内部类呢?主要原因:
1.内部类可以对同一个包中的其他类隐藏
2.内部类方法可以访问定义这个类作用域中的数据,包括原本私有的数据。
内部类一共有四种:静态内部类,实例内部类(成员内部类),匿名内部类,局部内部类。
1.静态内部类:
1.静态内部类是一种定义在另一个类里面的类,使用static修饰,类似于静态方法
2.静态内部类不需要外部类对象产生就能使用
3.静态内部类只能访问外部类的静态部分,不能访问外部类的实例部分。
4.不依赖于外部类,可直接创建静态内部类的实例对象。
5.静态内部类中可以访问外部类静态的成员,可以是任何修饰符修饰的。
6.外部类可以访问静态内部类的静态成员,可以是任何修饰符修水的。
7.外部类相要访问静态内部类的非静态成员,需要创建静态内部类实例对象,再通过实例对象去访问。
class OtherClass{
private int data1=12;
private static int data2=20;
static class Innerclass{//静态内部类
private int data3=25;
private static int data4=30;
public void test(){
OtherClass oc=new OtherClass();//实例外部类,访问外部非静态方法
System.out.println(oc.data1);
System.out.println(data2);//访问外部类的静态方法,可以直接访问
System.out.println(data3);
System.out.println(data4);
}
}
}
然后还要创建静态内部类实例:
外部类名.内部类名字 名称=new 外部类名.内部类名字();
public class Test {
public static void main(String[]args){
OtherClass.Innerclass oi=new OtherClass.Innerclass();//创建静态内部类实例
oi.test();
}
}
运行结果:
2.成员内部类:
成员内部类是最普通的内部类,它定义在另一个类的内部,类似于成员方法,成员内部类不能拥有静态域但是可以访问外部类的静态部分。
2.定义在外部类的内部,类似于成员方法,类和成员都不能使用static修饰。
3.依赖于外部类,需要通过外部类对象来创建成员内部类的实例对象。
4.可以拥有非静态的成员,可以是任何修饰符修饰的。
5.外部内可以访问成员内部类的成员,需要先创建成员内部类实例对象,再通过对象去访问。
public class Outclass {
public int data1=10;
public static int data2=20;
//成员内部类
class InnerClass {
public int data3=30;
public static int data4=40;
public void test(){
Outclass oc=new Outclass();//创建一个外部类
System.out.println(oc.data1);
System.out.println(data2);
System.out.println(data3);
System.out.println(data4);
}
}
}
然后还要创建内部类实例:
外部类名.内部类名字 名称=new 外部类名().new 内部类名字();
public class Test {
public static void main(String[] args) {
Outclass.InnerClass oi=new Outclass().new InnerClass();
oi.test();
}
}
静态内部类和成员内部类的区别:
作用域不同:
静态内部类的作用域仅限于外部类的本身,不依赖于外部类的实例
成员内部类的作用域依赖于外部类的实例
调用权限不同:
静态内部类可以访问外部类的所有静态成员,包括静态变量和静态方法(可以实例化外部类,完后通过外部类实例调用)
成员内部类可以访问外部类的所有成员,包括静态和非静态成员
实例化方式:
静态内部类可以独立于外部类的实例进行实例化,类似于普通类。
成员内部类必须依赖于外部类的实例才能进行实例化。
引用外部类:
创建对象:
静态内部类:外部类名称 静态内部类名称 名称=new 外部类名称.静态内部类名称();
成员内部类:外部类名称 成员内部类名称 名称=new 外部类名称().new 成员内部类名称();