Java身为面向对象程序设计语言,它的三大特性为:封装,继承,多态。封装即将对象的属性和行为封装起来,从而对客户隐藏其实现细节。再来详细介绍下继承和多态。
由类的继承可以引出向上转型,在JAVA继承中,为了避免出现C++继承两个类而出现多态混乱的场面,不知道调用哪个子类的方法和变量,故为了安全着想,在JAVA中,类的继承只能继承一个类,而接口为抽象的方法,并无具体实现,故可以继承多个接口,
向上转型中对象有以下特点:
<1>不能操作子类新增的成员变量和方法
<2>可以操作子类重写的成员变量和方法
<3>若子类重写父类方法,向上转型必定使用子类中重写的方法
<4>若上转型对象再强制转换为子类对象,则子类对象必定拥有子类的全部方法
Demo :
class Parent {
int a=2;
publicvoid init() {
System.out.println("1 init parent");
System.out.println("1 a="+a+"this.a="+this.a);
this.demo();
}
publicvoid demo() {
System.out.println("2 demo parent");
}
};
class addextends Parent{
int a=3;
public void init(){
super.init();
System.out.println("2a="+a+"this.a="+this.a);
System.out.println("3init son");
this.demo();
}
public void demo() {
System.out.println("4demo Son");
}
public static void main(String[] args) {
//Parent p = new Son();//1
add son = new add();//2
son.init(); // init(son) }
}
}
执行结果都为
1 init parent
1 a=2this.a=2
4 demo Son
2 a=3this.a=3
3 init son
4 demo Son
故无论是否向上转型的时候,它this都将调用子类中重写的方法,而对于变量则是执行到哪一个类就是哪个类的变量
在这也说下JAVA类的执行顺序:父类static先初始化->子类static初始化->main函数->父类普通变量的初始化->子类普通变量的初始化->父类构造函数->子类构造函数
Demo:
class Parent {
static {
int b;
System.out.println("static parentinit");
b=2;
}
public Parent(){
System.out.println("parentinit");
}
int a=getint();
int getint(){
int a=1;
System.out.println("generalparent init");
return a;
}
};
class addextends Parent{
int c=getint();
static {
int d;
System.out.println("static addinit");
d=4;
}
public add(){
System.out.println("addinit");
}
int getint(){
int c=1;
System.out.println("generalparent init");
return c;
}
public static void main(String[] args) {
add a=new add();
}
}
运行结果如下:
static parentinit
static add init
general parentinit
parent init
general parentinit
add init
抽象类和抽象方法(abstract)和接口(interface)
抽象类的定义:只要类里面有着抽象方法都称为抽象类,故抽象类内部可以有非抽象方法
抽象类不能实例化,如abstract add; add a=new add();这是错误的,但是抽象类是可以声明的,add a;这个是正确的。而接口里面都是抽象的,它只提供方法说明,不提供方法实现。
接口方法的名字,参数类型,数量,返回类型都要和借口完全一致
(而抽象类和接口的区别:1.语法层面上的区别
1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
2.设计层面上的区别
1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。
2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。)
内部类
1. 成员内部类:成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。当内部类想访问外部同名变量,同名方法时,就要使用外部类.this.成员变量,而外部想访问内部类的时候,就要酱紫
//第一种方式Outter outter = new Outter();
Outter.Inner inner = outter.newInner(); //必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 =outter.getInnerInstance();
2. 局部内部类:局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
3.匿名内部类:匿名内部类参数必须为final(解释:首先,这关系到java对象中的生命周期的问题。
基础数据类型和引用变量(不是被引用的对象)做局部变量时(这里是和做为变量成员变量区别,它们作为成员变量后就作为对象的一部分和对象的生命周期相同了);它们的生命中周期是有作用域的,它没有受生命周期影响这一说,但是同样在这一作用域创建的对象的生命周期并不受作用域的限制。
局部变量的生命周期与局部内部类的对象的生命周期的不一致。
内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命,拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。
复制保证生命周期延续,final保证引用一致。
)
Demo:
history_bt.setOnClickListener(newOnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
或者这样的demo:
private voidsetListener()
{
history_bt.setOnClickListener(new Listener1());
}
class Listener1 implementsView.OnClickListener{
@Override
public void onClick(View v) {
//TODO Auto-generated method stub
}
}
4.静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
注意:若想在内部类中声明static成员,内部类必须为static