1.面向对象的主要特征包括:抽象,继承,封装,多态
2.继承主要有如下几个特征:
1)不支持多重继承
2)子类只能继承父类非私有(public,protected)成员变量和方法
3)当子类的成员变量和父类的成员变量同名时,子类中的成员变量会覆盖父类中的成员变量,而不会继承。
4)当子类中的方法与父类中的方法有相同的函数签名时,子类会覆盖父类的方法而不会继承
3.组合和继承的区别
组合是指在新类里面创建原有类的对象;
组合和继承的区别:
例如:Car表示汽车对象,Vehicle表示交通工具,Tire表示轮胎对象
is-a关系用继承表示
has-a关系用组合表示
4.多态实现的机制是什么?
java中多态主要有以下两种表现方式:
1)方法的重载:一个类中有多个同名的方法,编译时多态
2)方法的覆盖:子类覆盖父类的方法,运行时多态
例1:
package com.zcl.test;
class Base{
public Base(){
g();
}
public void f(){
System.out.println("Base() f");
}
public void g(){
System.out.println("Base() g");
}
}
class Derived extends Base{
public void f(){
System.out.println("Derived() f");
}
public void g(){
System.out.println("Derived() g");
}
}
public class Test {
public static void main(String[] args) {
Base b = new Derived();
b.f();
b.g();
}
}
结果:
Derived() g
Derived() f
Derived() g
此外,只有类中的方法才有多态的概念,类中成员变量是没有多态的概念的
package com.zcl.test;
class Base{
public int i = 1;
}
class Derived extends Base{
public int i = 2;
}
public class Test {
public static void main(String[] args) {
Base b = new Derived();
System.out.println(b.i);
}
}
结果:
1
由此可见,成员变量是无法实现多态的,成员变量的值取决于所定义变量的类型,这是在编译期确定的。
5.重载和重写的区别 ?
在使用重载的时候需要注意:
1)重载是通过不同的方法参数来区分的
2)不能通过方法的访问权限,返回值类型和抛出的异常类型进行重载
3)对于继承来说,如果基类方法是private,就不能在派生类中进行重载;如果派生类也定义了一个同名函数,则只是一个新的方法。
在使用覆盖时需要注意:
1)派生类中的覆盖方法必须与基类中被覆盖方法有相同的函数名和参数。
2)派生类中的覆盖方法的返回值必须与基类中被覆盖方法的返回值相同。
3)派生类中的覆盖方法所抛出的异常必须与基类中被覆盖的方法所抛出的异常一致。
4)基类中被覆盖的方法不能为private,否则其子类只是定义了一个方法。
重载和覆盖的区别:
1)覆盖是子类和父类的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。
2)覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
3)覆盖要求参数列表相同,重载要求参数列表不同。
4)覆盖关系中,调用方法体是根据对象的类型来决定;而重载关系是根据调用时的实参表与形参表来选择方法体的。
例1:如下代码的运行结果是:
package com.zcl.test;
class Super{
public int f(){
return 1;
}
}
public class SubClass extends Super{
public float f(){//xxxx
return 2f;
}
public static void main(String[] args) {
Super s = new SubClass();
System.out.println(s.f());
}
}
编译错误:因为函数是不能以返回值来区分的。
6.抽象类和接口的异同:
相同点:
1)都不能被实例化
2)接口的实现类或抽象类的子类都只有在实现了接口或抽象类中的方法之后才可以被实例化。
不同点:
1)接口只有定义,没有实现
2)接口需要实现(implements),抽象类需要继承(extends)
3)接口强调has-a,抽象类强调is-a
4)接口中的成员变量默认是:public static final,而且必须赋初值;成员方法都是public abstract
5)接口用于实现常用功能,抽象类用于充当公共类的角色。
7:内部类有哪些?(静态内部类;成员内部类;局部内部类;匿名内部类)
package com.zcl.test;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
class outerClass{
static class innerClass{}//静态内部类
}
class outerClass1{
class innerClass{};//成员内部类
}
class outerClass2{
public void menberFunction(){
class innerClass{}//局部内部类
}
}
public class MyFrame extends Frame{
public MyFrame(){
addWindowListener(new WindowAdapter() {//匿名内部类
public void windowClosing(WindowEvent e){
dispose();
System.exit(0);
}
});
}
}
1)静态内部类可以不依赖外部类实例而被实例化;不能与外部类有相同的名字,只能访问外部类中的静态成员和静态方法。
2)成员内部类可以自由引用外部类的属性和方法,不可以定义静态的属性和方法。
3)局部内部类:定义在代码块中的类,只能访问方法中被定义为final类型的局部变量。
4)匿名内部类是一种没有类名的内部类,不适用关键字class,extends,implements,没有构造函数,必须继承其他类或实现其他接口,一般用于GUI图形用户界面编程中实现事件处理等。
匿名内部类注意事项:
1)匿名内部类不能有构造函数
2)匿名内部类不能定义静态成员,方法和类
3)匿名内部类不能是public,protected,private,static
4)只能创建匿名内部类的一个实例
5)一个匿名内部类一定是在new的后面,这个匿名内部类必须继承一个父类或实现一个接口
6)匿名内部类为局部内部类。
8.如何获取父类的类名?
java语言提供了获取类名的方法getClass().getName()
例1:
package com.zcl.test;
public class Test {
public void test(){
System.out.println(this.getClass().getName());
}
public static void main(String[] args) {
new Test().test();
}
}
结果:
com.zcl.test.Test
例2:通过调用父类的getClass().getName()方法可行吗?
package com.zcl.test;
class A{}
public class Test extends A {
public void test(){
System.out.println(super.getClass().getName());
}
public static void main(String[] args) {
new Test().test();
}
}
结果:
不可行
com.zcl.test.Test
原因:
java语言中任何类都继承自Object类,getClass方法在Object中被定义为final和native,子类不能覆盖。
并且getClass()含义是返回运行时类,程序实际运行的是Test而不是A
例3:可以通过java的反射机制
package com.zcl.test;
class A{}
public class Test extends A {
public void test(){
System.out.println(this.getClass().getSuperclass().getName());
}
public static void main(String[] args) {
new Test().test();
}
}
结果:
com.zcl.test.A
9:this和super有什么区别?
在java语言中,this用来指向当前实例对象,它的一个非常重要的作用是:区分对象的成员变量和方法的形参。
因为当方法的形参与成员变量的名字相同时,就会覆盖成员变量。
例1:
class People{
String name;
//正确的写法
public People(String name){
this.name = name;
}
//错误的写法
public People(String name){
name = name;
}
}
super可以访问父类的方法或成员变量。当子类的方法或成员变量与父类有相同名字时也会覆盖父类的方法或成员变量。
例2:
package com.zcl.test;
class Base{
public void f(){
System.out.println("Base:f()");
}
}
class Sub extends Base{
public void f(){
System.out.println("Sub:f()");
}
public void subf(){
f();
}
public void basef(){
super.f();
}
}
public class Test{
public static void main(String[] args) {
Sub s = new Sub();
s.subf();
s.basef();
}
}
结果:
Sub:f()
Base:f()
例3:下面程序的运行结果:
package com.zcl.test;
class Base{
public Base(){
System.out.println("Base");
}
}
class Sub extends Base{
public Sub(){
System.out.println("Sub");
super();//xxxx编译错误
}
}
public class Test{
public static void main(String[] args) {
Base s = new Sub();
}
}
当子类构造函数需要显示调用父类的构造函数时,super()必须为构造函数中的第一条语句。
super();
System.out.println("Sub");