面向对象(下):
1. 代码块:
- 实例代码块
示例:
{
}
代码块中的代码每次new对象时都会执行
- 静态代码块
示例:
static {
}
静态代码块会在类加载时执行,且只执行一次
执行顺序:
- 静态代码块>实例代码块>构造器
- 父类静态->子类静态->父类实例->父类构造->子类实例->子类构造
2. super关键字:
super是子类调用父类方法的关键字,只能在子类中执行
子类可以通过super调用父类的方法和属性
示例:
//鸟类
public class Bird {
private String name;
public void fly() {
System.out.println("大多数鸟类都会飞");
}
}
//鹰类
public class Eagle extends Bird{
@Override
public void fly() {
super.fly();
}
public static void main(String[] args) {
Eagle eagle = new Eagle();
eagle.fly();
}
}
运行结果:
注意:
-
super和this不能同时在一个构造器内调用同样的属性
-
super一定要声明在构造器的第一行
-
在构造器中,如果没显式的super方法,则默认有一个空参的super方法
3. 多态:
多态的目的是让父类的引用调用子类继承的方法
条件:
-
是继承关系
-
子类重写了父类的方法
-
父类调用了子类重写后的方法
示例:
//鸟类
public class Bird {
private String name;
public void fly() {
System.out.println("大多数鸟类都会飞");
}
}
//鹰类
public class Eagle extends Bird{
@Override
public void fly() {
System.err.println("鹰击长空");
}
public static void main(String[] args) {
Bird eagle = new Eagle();
eagle.fly();
}
}
运行结果:
可以看到,在main方法中,虽然等号左边是鸟类,但等号右边赋值却是鹰类
这样一来,该对象在调用fly()方法时,会自动调用子类的fly()方法
但是这个类仍然是鸟类
通俗来说就是,"编译时右边,运行时左边"
以上的现象叫做对象的向上转型
向上转型就是父类的引用可以调用子类继承的方法
示例:
Person stu = new Student();//Student类继承了Person类
但是父类只能调用子类的方法,如果要调用子类的一些特有的属性和方法时,向上转型是不适用的
这个时候就需要向下转型
示例:
Student stu1 = (Student)stu
如果只有这样一行代码,很难判断两个类之间是否是同源(继承)关系,从而容易引发异常
所以可以这样写:
if (stu instanceof Student) {
Student stu1 = (Student)stu
}
这样一来就可以调用子类中的一些特有属性和方法了
4. 抽象类
抽象类是指被修饰符abstract修饰的类
抽象类使用的前提:继承性
说明:
-
抽象类是没有实例化对象的
-
抽象类中一定有构造器,便于子类实例化时调用
-
抽象类中只有方法的声明,没有方法体
-
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法。
示例:
public abstract void fly();
- 子类必须重写抽象类中用abstract修饰的方法,否则会报错
其实抽象类就是为了子类的继承而使用的,其目的就是为了功能的扩展,延续多态性
注意:
-
abstract不能用来修饰:属性、构造器等结构
-
abstract不能用来修饰 私有方法、静态方法、final修饰的方法、final修饰的类
5. 接口(Interface)
接口,类似于现实生活中的USB接口,Type-C接口,有自己的一套规范,可以接入不同的设备
说明:
-
接口是Java中的规范,标准
-
接口没有实例化对象
-
A implements B,说明A实现B,A需要实现接口B中的方法
-
接口中的变量默认都被修饰为常量
-
接口中的方法默认都被修饰为抽象方法
-
一个类可以实现多个接口
-
接口不能实现接口,但是可以继承接口
-
jdk1.8新特性:加了default、static修饰的方法
接口与抽象类的区别:
不同点:
类是单继承,接口是多实现
相同点:
不能实例化;都可以包含抽象方法
6. final关键字
final关键字是用来修饰类,方法,属性的
被final修饰的数据有以下几个特点
-
被修饰的类无法被继承
-
被修饰的方法不能被重写
-
被修饰的属性必须被赋值且赋值后不能被修改
-
被final 和 static 同时修饰的变量叫做常量,命名需要全部大写
7. 内部类
内部类就是在一个类内部声明的类
内部类一共分为三种
-
静态内部类
静态内部类只需要在包含类的main方法中生成对象就可以调用其属性和方法
举例:
//包含类
public class A {
//静态内部类
static class B{
private String name;
@Override
public String toString() {
// TODO Auto-generated method stub
return name;
}
}
public static void main(String[] args) {
B b = new B();
b.name = "静态内部类";
System.out.println(b);
}
}
运行结果:
- 非静态内部类
非静态内部类需要先声明包含类,再声明内部类才能调用其方法和属性
举例:
//包含类
public class A {
//非静态内部类
class B{
private String name;
@Override
public String toString() {
// TODO Auto-generated method stub
return name;
}
}
public static void main(String[] args) {
A.B b = new A().new B(); //注意声明方式的不同
b.name = "非静态内部类";
System.out.println(b);
}
}
运行结果:
- 匿名内部类
匿名内部类就是在一个类中声明,没有名字的类
举例:
//包含类
public class A {
//方法返回匿名内部类
public B returnB() {
return new B() {
@Override
public String toString() {
// TODO Auto-generated method stub
return "我是匿名内部类";
}
};
}
public static void main(String[] args) {
A a = new A();
System.out.println(a.returnB());
}
}
class B{
public String toString() {
return null;
}
}
可以看到,B类在A类中没有声明变量名,直接重写了方法并且调用
好处是内部类声明过后将会被JVM当作垃圾直接处理
JDK中awt包中的例子:
//包含类
public class A extends Frame{
//声明按钮
Button button = new Button();
//构造器
public A() {
//匿名内部类为按钮绑定事件监听
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
});
}
}