day8-面向对象高级
-
多态
-
接口
-
内部类
多态
在java中,方法和属性都是可以以多态的形式存在的,方法的多态主要体现方法的重写与重载;属性的多态一般表现形式为父类引用指向子类对象(向上转型);一个引用类型变量既可以指向该引用类型自身,也可以指向该类型子对象,该操作称之为多态,或者动态绑定。
public abstract class Animal{
public abstract void sleep();
}
public class Dog extends Animal{
public void sleep(){
System.out.println("呼呼大睡。。。。");
}
}
public class Test{
public static void main(String[] args){
//父类引用指向子类对象
Animal a = new Dog();
}
}
多态的优势:
-
降低了类之间的耦合
-
面向抽象编程
-
提高程序的可扩展性
多态中关于对象转型问题:
可以使用父类引用指向子类对象(上转型);反过来子类引用可以指向父类对象(下转型),但是被下转型的父类对象原本就应该是子类的对象,否则会出现:java.lang.ClassCastException异常(造型失败)
//上转型 Animal a = new Dog("旺财"); Dog dog = (Dog)new Animal(); //java.lang.ClassCastException //下转型 Dog d = (Dog)a;
接口(interface)
interface,是一种比抽象类更纯粹的结构,接口中只能存在抽象方法和常量(接口是一组抽象方法和常量的集合),接口并不是类,所以没有构造器;一般可以由具体类对接口进行实现,并且具体类必须实现接口中的所有方法
接口语法:
<modifier> interface <name>[extends <superinterface>] {
<attribute_declarations> <method_declarations>
}
接口(Flyable.java):
interface Flyable{
//常量定义(系统自动补充:public static final String TYPE = "bird")
String TYPE = "bird";
//抽象方法定义(系统自动补充:public abstract void fly())
void fly();
}
实现类(Bird.java):
class Bird implements Flyable{
public void fly(){
System.out.println("自由自在翱翔天际!");
}
}
以上为一个标准接口的定义以及实现类对接口的具体实现,在java中实现类还可以实现多个接口以弥补类只能单继承的缺陷,例如还有一个接口Singable,里面包含一个sing方法,此时实现类除了实现Flyable接口外还能实现Singable接口,但是实现类必须对所有接口的方法进行实现,如下:
接口2(Singable):
interface Singable{
public void sing();
}
实现类(Bird.java)
class Bird implements Flyable,Singable{
public void fly(){
System.out.println("自由自在翱翔天际!");
}
public void sing(){
System.out.println("你是我的小呀小苹果~~");
}
}
接口与抽象类的区别
接口是一种更纯粹的抽象结构
接口是对行为的抽象(接口描述动词),抽象类是对一些类型的抽象(抽象类描述名词)
一个类只能存在一个直接父类,但是类可以实现多个接口(实现类必须实现所有的方法)
接口可以继承接口,并且能同时继承多个接口,抽象类只能直接继承一个抽象类
内部类
java中可以在一个类的内部定义属于该类的从属类,从属类具备访问外部类的成员的能力,内部类提供了比方法更完整封装性,内部类主要包含以下几种:
-
成员内部类
-
局部内部类
-
静态内部类
-
匿名内部类
成员内部类
public class Outter {
private String name = "旺财";
public void m1(){
InnerClass1 ic = new InnerClass1();
System.out.println("获取内部类的成员变量:"+ic.name2);
}
/**
* 成员内部类
* @author mrchai
*
*/
private class InnerClass1{
private String name2 = "来福";
public void m2(){
//内部类可以直接使用外部类的成员变量与方法
System.out.println("成员内部类的方法:"+name);
Outter.this.m1();
}
public void m1(){
System.out.println("内部类的m1方法");
}
}
public static void main(String[] args) {
Outter.InnerClass1 in = new Outter().new InnerClass1();
in.m2();
}
}
局部内部类
public class Outter2 {
private String name = "旺财";
public void m(){
//局部变量如果在内部类中使用则必须使用final修饰
final int i = 10;
//局部内部类不允许使用访问修饰符修饰
class Inner{
public void m2(){
System.out.println("hello,局部内部类:"+i);
}
}
//局部内部类的访问仅限于声明区域
new Inner().m2();
}
}
静态内部类
public class Outer3 {
private String name1 = "旺财";
static class Inner{
String name2 = "来福";
public void m(){
System.out.println("外部类的成员变量:"+new Outer3().name1);
}
}
public void m2(){
new Inner().m();
}
public static void main(String[] args) {
Outer3.Inner in = new Outer3.Inner();
in.m();
}
}
匿名内部类
匿名内部类顾名思义,即没有名字的内部类,一般表现形式为使用父类的引用指向你一个匿名对象,方法的实现在匿名语句块中完成
Animal a = new Animal() {
@Override
public void sleep() {
System.out.println("休眠一下");
}
};
//输出地址非Animal对象,而是包含了“$”符号的对象地址(即内部类)
System.out.println(a);
a.sleep();
Cat c = new Cat(){
@Override
public void eat() {
System.out.println("吃猫粮");
}
};
/*
针对以下接口创建匿名内部类对象
interface Sportable{
void run();
void jump();
}
*/
匿名内部类与回调机制
Button.java
public class Button {
//内部接口
public interface OnClickListener{
//回调函数(钩子函数)
void click();
}
public void setOnClickListener(OnClickListener lis){
System.out.println("准备触发");
lis.click();
System.out.println("清理资源");
}
}
ButtonTest.java
public class ButtonTest{
public static void main(String[] args) {
Button btn = new Button();
//匿名内部类使用
btn.setOnClickListener(new OnClickListener() {
//回调机制
@Override
public void click() {
System.out.println("事件被触发。。。。");
}
});
}
}
关于内部类注意事项
内部类可以使用外部类的成员变量和方法
局部内部类如果需要使用外部方法(或者语句块)的局部变量,该局部变量必须使用final修饰(延长局部变量的生命周期)
局部内部类的使用范围仅限于声明区域
静态内部类中不能直接使用外部类的实例方法实例变量,创建外部类对象,才能通过对象调用