抽象类
- 抽象类的概述
回想前面我们的猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实这是不对的。
为什么呢?因为,我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。
所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。
同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。 - 抽象类的特点
a:抽象类和抽象方法必须用abstract关键字修饰
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
b:抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
c:抽象类中可以有构造方法,抽象类不能进行实例化,那么要构造方法有什么作用呢?
用于子类访问父类数据时的初始化
d:抽象类不能直接实例化那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
e:抽象类的子类
要么是抽象类
要么重写抽象类中的所有抽象方法 - 抽象类的成员特点
a:成员变量:既可以是变量,也可以是常量。
b:构造方法:有。
用于子类访问父类数据的初始化。
c:成员方法:既可以是抽象的,也可以是非抽象的。 - 抽象类的成员方法特性:
a:抽象方法 强制要求子类做的事情。
b:非抽象方法 子类继承的事情,提高代码复用性。
案例
案例一:
//一旦一个类中,有了抽象方法,此类必须为抽象类
public abstract class Animal {
public Animal() {
System.out.println("父类的构造方法执行了");
}
//abstract 抽象的,可以修饰类,修饰方法
public abstract void eat(); //抽象方法,此方法没有方法实现
public abstract void sleep();
//抽象类中既可以有抽象方法,也可以非抽象方法
public void show(){
System.out.println("这是父类的一个非抽象方法");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫爱吃鱼");
}
@Override
public void sleep() {
System.out.println("猫白天睡觉");
}
}
public class MyTest {
public static void main(String[] args) {
// new Animal();//抽象类不能直接创建对象
//我们可以采用多态间接的去实例化抽象类
Animal an=new Cat();
an.eat();
an.sleep();
an.show();
}
}
注意:
抽象类不能直接创建对象
我们可以采用多态间接的去实例化抽象类
- 抽象类理解:就是被abstract所修饰的类,父类将所有子类的共性功能向上抽取后,他并不知道,每个子类对这个共性功能的具体实现,所以没有必要在父类中,给出共性功能的具体实现,而是给出声明即可,所谓给出功能的声明,就是将此功能抽象出来,然后强制子类必须重写,抽象的功能。
- 抽象类注意事项:
- 一旦一个类中,有了抽象方法,那么此类必须为抽象类
- 一个抽象类中可以没有抽象方法
抽象类中既可以有抽象方法,也可以有非抽象方法,抽象方法,强制子类重写,非抽象方法,可以让子类继承下去用 - 抽象类不能直接实例化,可以采用多态的方式,间接实例化
- 抽象类的子类,要么重写父类中所有的抽象方法,要么自己也是一个抽象类。
- 抽象类中有构造方法,用来子类初始化父类要用
案例二:
public abstract class A {
public abstract void a();
public abstract void c();
}
public abstract class B extends A{
public abstract void d();
}
public class C extends B{
@Override
public void d() {
}
@Override
public void a() {
}
@Override
public void c() {
}
}
注意:子类c要重写抽象类b和抽象类a中的所有抽象方法
案例三:
public abstract class Person {
public String name;
public int age;
public abstract void eat();
public abstract void sleep();
public void playGame(){
System.out.println("玩游戏");
}
}
public class Teacher extends Person {
@Override
public void eat() {
System.out.println("老师爱吃搅团");
}
@Override
public void sleep() {
System.out.println("老师经常失眠");
}
}
public class Student extends Person{
@Override
public void eat() {
System.out.println("学生爱吃烤串");
}
@Override
public void sleep() {
System.out.println("学生通宵不寐");
}
public void watchTV(){
System.out.println("学生看电视");
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Student();
p.name = "董永";
p.age = 29;
System.out.println(p.name + "====" + p.age);
p.sleep();
p.playGame();
p.eat();
((Student) p).watchTV();
System.out.println("------------------------");
p = new Teacher();
p.name = "沈某某";
p.age = 20;
System.out.println(p.name + "===" + p.age);
p.eat();
p.eat();
p.playGame();
}
}
案例四:
案例演示
假如我们在开发一个系统时需要对员工(Employee) 类进行设计,员工包含3个属性:姓名、工号以及工资(salary)。
经理(Manager) 也是员工,除了含有员工的属性外,另为还有一个奖金(bonus) 属性。
然后定义工作的方法.
请使用继承的思想设计出员工类和经理类。
public abstract class Person {
//姓名、
//
//工号以及工资(salary)。
public String name;
public int num;
public double salary;
public abstract void work();
}
public class Employee extends Person{
@Override
public void work() {
System.out.println("员工敲代码");
}
}
public class Manager extends Person{
public double bonus;
@Override
public void work() {
System.out.println("经理管理员工");
}
}
public class MyTest {
public static void main(String[] args) {
Person p = new Employee();
p.name="张三";
p.num=1;
p.salary=2000;
System.out.println(p.name+"=="+p.num+"==="+p.salary);
p.work();
System.out.println("--------------------");
p=new Manager();
p.name = "lisi";
p.num = 2;
p.salary = 4000;
((Manager) p).bonus=2000;
System.out.println(p.name+"==="+((Manager) p).bonus+"==="+p.num);
p.work();
}
}
案例五:
public class MyTest {
public static void main(String[] args) {
}
}
abstract class A{
int num=100;
public static final int num2=1000;
public A(int num) {
this.num = num;
}
}
抽象类面试题
1. 抽象类中的成员变量 即可定义变量也可以定义常量
抽象类中有构造方法,用来子类初始化化父类
抽象类中既可以有抽象方法,也可以有非抽象方法
2. 一个类如果没有抽象方法,可不可以定义为抽象类 ? 如果可以,有什么意义 ?
可以 外界不能直接创建对象
3. abstract不能和哪些关键字共存 ?
不能和private 共存 矛盾
不能和 final 共存 矛盾
不能和 static 共存 没有意义
接口
- 概述
继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。
但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。
而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。
所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可 - 接口特点
a:接口用关键字interface表示 格式: interface 接口名 {}
b:类实现接口用implements表示 格式: class 类名 implements 接口名 {}
c:接口不能实例化
那么,接口如何实例化呢?
按照多态的方式来实例化。
d:接口的子类
a:可以是抽象类。但是意义不大。
b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案)
接口的成员特点
- 接口的成员特点
成员变量;只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
案例
案例一:
public abstract class Animal {
public abstract void eat();
}
public interface CalcInterface {
//用来定义额外功能
public abstract void calc();
}
public class Cat extends Animal implements CalcInterface{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catcheMouse(){
System.out.println("猫抓老鼠");
}
@Override
public void calc() {
System.out.println("猫经过不断的努力学习,会做算术了");
}
}
public class Dog extends Animal implements CalcInterface{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void lookDoor(){
System.out.println("狗看门");
}
@Override
public void calc() {
System.out.println("狗经过自己的学习,也学会了做算术");
}
}
public class MyTest {
public static void main(String[] args) {
Cat cat = new Cat();
Animal an = cat;
an.eat();
// CalcInterface 是猫的一个父接口,猫类也是父接口的一个子类
CalcInterface calcInterface = cat;
calcInterface.calc();
//多态
CalcInterface c = new Dog();
c.calc();
//接口不能new 对象
}
}
案例二:
public class MyTest {
public static void main(String[] args) {
//接口中成员变量的特点
//接口中的成员变量全是静态的公共常量
//接口中没有构造方法的
//接口中没有非抽象方法,全是抽象方法
int a = A.A;
System.out.println(a);
int num = A.num;
}
}
interface A{
//接口中成员变量前面有默认的修饰符 public static final
int num=100;
public static final int A=1000;
//方法前面存在默认修饰符 public abstract
public abstract void hehe();
void test();
}
注意:
CalcInterface 是猫的一个父接口,猫类也是父接口的一个子类
- 类与类,类与接口,接口与接口的关
a:类与类:
继承关系,只能单继承,可以多层继承。
b:类与接口:
实现关系,可以单实现,也可以多实现。
并且还可以在继承一个类的同时实现多个接口。
c:接口与接口:
继承关系,可以单继承,也可以多继承。
案例三
public class MyTest {
public static void main(String[] args) {
//类跟类之间的关系
// 类跟类是继承关系,只能是单继承,支持多层继承
// 类跟接口是实现关系 既可以实现一个接口,也可以实现多个接口,实现接口,必须重写接口中所有的抽象方法
// 接口跟接口的关系,继承关系,而且可以多继承
}
}
class Fu{}
interface A{
void a();
}
interface C{
void c();
}
class B extends Fu implements A,C{
@Override
public void a() {
}
@Override
public void c() {
}
}
interface E{
void e();
}
interface F{
void f();
void ff();
}
interface G extends E,F{
void g();
void gg();
}
class V implements G{
@Override
public void e() {
}
@Override
public void f() {
}
@Override
public void ff() {
}
@Override
public void g() {
}
@Override
public void gg() {
}
}
抽象类和接口的区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以抽象
关系区别:
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
设计理念区别:
抽象类 : 被继承体现的是:”is a”的关系。 抽象类中定义的是该继承体系的共性功能。
接口 : 被实现体现的是:”like a”的关系。 接口中定义的是该继承体系的扩展功能。
注意:JDK1.8之后在接口中提供了用default修饰的方法,可以给出功能的具体实现,子类可以继承下去用
案例四:
public class MyTest2 {
//JDK1.8之后,接口中可以定义默认方法
public static void main(String[] args) {
C c= new C();
A a=c;
a.test();
a.test2();
a.test3();
B b=c;
b.test22();
b.test333();
}
}
interface A{
void hehe();
public default void test(){
System.out.println("JDK1.8之后接口中,可以定义默认方法,可以有方法的具体实现");
}
public default void test2() {
System.out.println("JDK1.8之后接口中,可以定义默认方法,可以有方法的具体实现");
}
public default void test3() {
System.out.println("JDK1.8之后接口中,可以定义默认方法,可以有方法的具体实现");
}
}
interface B {
void hehe();
public default void show() {
System.out.println("JDK1.8之后接口中,可以定义默认方法,可以有方法的具体实现");
}
public default void test22() {
System.out.println("JDK1.8之后接口中,可以定义默认方法,可以有方法的具体实现");
}
public default void test333() {
System.out.println("JDK1.8之后接口中,可以定义默认方法,可以有方法的具体实现");
}
}
class C implements A,B{
@Override
public void hehe() {
}
@Override
public void test22() {
}
}
案例五
案例演示
//动物类:姓名,年龄,吃饭,睡觉。
//动物培训接口:跳高
//猫继承动物类
//狗继承动物类
// 部分猫继承猫类并实现跳高接口
//部分狗继承狗类并实现跳高接口
//
//通过抽象类测试基本功能。
//通过接口测试扩展功能。
public abstract class Animal {
public String name;
public int age;
public abstract void eat();
public abstract void sleep();
}
public interface JumpInterface {
void jump();
}
public class Cat extends Animal{
@Override
public void eat() {
}
@Override
public void sleep() {
}
}
public class KittyCat extends Cat implements JumpInterface{
@Override
public void eat() {
System.out.println("kitty猫吃蛋糕");
}
@Override
public void sleep() {
System.out.println("kitty猫整体睡觉");
}
@Override
public void jump() {
System.out.println("kitty猫学会跳高了");
}
}
public class TomCat extends Cat{
@Override
public void eat() {
System.out.println("汤姆猫想吃杰瑞");
}
@Override
public void sleep() {
System.out.println("汤姆猫假装睡觉");
}
public void actor(){
System.out.println("汤姆猫是一个演员");
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("吃饭");
}
@Override
public void sleep() {
System.out.println("睡觉");
}
}
public class WangCaiDog extends Dog implements JumpInterface{
@Override
public void eat() {
System.out.println("旺财吃的是狗粮");
}
@Override
public void sleep() {
System.out.println("旺财晚上睡觉");
}
public void lookDoor(){
System.out.println("旺财看门");
}
@Override
public void jump() {
System.out.println("旺财学会里跳高");
}
}
public class XiaoTianDog extends Dog{
@Override
public void eat() {
System.out.println("哮天犬吃的是天宫套餐");
}
@Override
public void sleep() {
System.out.println("哮天犬不睡觉");
}
public void fashu(){
System.out.println("哮天犬会法术");
}
}
public class MyTest {
public static void main(String[] args) {
KittyCat cat = new KittyCat();
Animal an = cat;
an.name = "kitty";
an.age = 1;
System.out.println(an.name + "===" + an.age);
an.eat();
an.sleep();
JumpInterface jumpInterface = cat;
jumpInterface.jump();
System.out.println("---------------");
TomCat tomCat = new TomCat();
an = tomCat;
an.name = "tom";
an.age = 2;
System.out.println(an.name + "===" + an.age);
an.eat();
an.sleep();
System.out.println("----------------------------------");
WangCaiDog wc = new WangCaiDog();
an = wc;
an.name = "旺财";
an.age = 3;
System.out.println(an.name + "===" + an.age);
an.sleep();
an.eat();
//WangCaiDog w= (WangCaiDog) an;
//w.lookDoor();
((WangCaiDog) an).lookDoor();
jumpInterface = wc;
jumpInterface.jump();
System.out.println("-----------------");
XiaoTianDog xiaoTianDog = new XiaoTianDog();
an = xiaoTianDog;
an.name = "哮天犬";
an.age = 10000;
an.eat();
an.sleep();
//向下转型
((XiaoTianDog) an).fashu();
}
}
类和接口的传参和返回值
案例
案例一:
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
//如果你以后看到一个方法的形参要一个类 类型,你就传一个该类的对象
int num=2;
set(student,num);
student.show(new Student(),100);
System.out.println(student.num);//100
}
public static void set(Student student,int num){
student.num=num;
}
}
class Student{
int num=10;
public void show(Student student,int num){
student.num=num;
}
}
案例二:
public class MyTest {
public static void main(String[] args) {
int num=1;
Zi zi = new Zi();
//如果你以后看到一个方法的形参要一个抽象类 类型,那么你就传一个该抽象类的子类对象
set(new Zi(),num);
zi.show(188);
System.out.println(zi.num); //
}
public static void set(Fu fu,int num){
fu.num=num;
}
}
abstract class Fu{
int num=100;
public abstract void show(int num);
}
class Zi extends Fu{
int num=10;
@Override
public void show(int num) {
this.num=num;
}
}
案例三:
public class MyTest {
public static void main(String[] args) {
int num=1;
//如果你以后看到一个方法的形参要一个接口类型,你要传一个该接口的子类对象
B b = new B();
set(b,num);
// b.show(109);
System.out.println(b.a);//10
System.out.println(b.NUM); //100
System.out.println(A.NUM); //100
System.out.println(B.NUM); //100
}
public static void set(A a,int num){
new B().a=num;
a.show(num);
}
}
interface A{
public static final int NUM=100;
void show(int num);
}
class B implements A{
int a=10;
@Override
public void show(int num) {
this.a=num;
}
}
案例四:
public class MyTest {
public static void main(String[] args) {
int num = 100;
A a = new A();
A a1 = a.getA(num);
System.out.println(a.num);// 1
System.out.println(a1.num); // 1
System.out.println(a);
System.out.println(a1);
System.out.println(a == a1);
}
public static A getAA(A a, int num) {
a.num = num;
return a;
}
}
class A {
int num = 1;
//如果你以后看到一个方法的返回值类型 是一个 类 类型,你就返回该类的一个对象
public A getA(int num) {
A a = new A();
a.num = num;
// return a;
return this;
}
}
案例五:
public class MyTest {
public static void main(String[] args) {
MyClass myClass = new MyClass();
int num=2;
MyInterface myInterface = get(myClass, num);
myClass.show(109);
System.out.println(myClass.num); //
System.out.println(myInterface.NUM);//
}
//如果你以后看到一个方法的返回值类型,要一个接口类型,你就返回该接口的一个子类对象
public static MyInterface get(MyClass myClass,int num){
myClass.num=num;
return myClass;
}
}
interface MyInterface{
int NUM=100;
void show(int num);
}
class MyClass implements MyInterface{
int num=1;
@Override
public void show(int num) {
this.num=num;
}
}
案例六:
public class MyTest {
public static void main(String[] args) {
Zi zi = new Zi();
Fu fu = zi.getFu(zi, 109);
System.out.println(zi.num); //109
System.out.println(fu.num); //109
System.out.println(zi);
System.out.println(fu);
}
}
abstract class Fu {
int num = 10;
}
class Zi extends Fu {
//如果你以后看到一个方法的返回值类型,要一个抽象类 类型,你就返回一个该抽象类的子类对象
public Fu getFu(Fu fu, int num) {
fu.num = num;
// return new Zi();
return this;
}
}
案例七:
public class MyTest {
public static void main(String[] args) {
//链式编程
//Student student = new Student();
//Student student1 = student.getStudent(new Student(), 100);
//student1.show(109);
//链式编程:当你调用完一个方法之后,方法的返回值又是一个对象,那么你就可以紧接着打点再去调用对象的方法
Student student = new Student();
new Student().getStudent(student, 100).show(109);
System.out.println(student.num); //
}
}
class Student {
int num = 10;
public Student getStudent(Student stu, int num) {
stu.num = num;
return this;
}
public void show(int num) {
this.num = num;
}
}
注意链式编程
案例八:
public class Teacher {
protected void show(){
System.out.println("学生类里面的show方法");
}
public void hehe(){
show();
}
}
public class MyTest {
public static void main(String[] args) {
new Teacher().show();
}
}
**注意:**不同包下的类访问调用需要导包,同一包下的类使用无需导包;
import关键字
- 导包的概述
不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能 - 导包格式
import 包名;
注意:
这种方式导入是到类的名称。
虽然可以最后写*,但是不建议。
案例
import org.westos.demo9.Teacher;
public class Son extends Teacher {
@Override
protected void show() {
super.show();
}
}
package org.westos.demo91;
import org.westos.demo9.Teacher;
public class MyTest {
public static void main(String[] args) {
//不同包下的类,进行访问需要导包
Teacher teacher = new Teacher();
// teacher.show();
}
}
- 四种权限修饰符
四种权限修饰符: private(私有的) , 默认 , protected(受保护的) , public(公共的)
类及其组成所使用的常见修饰符)(理解)
A:修饰符:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
抽象修饰符:abstract
B:修饰类的关键字:
权限修饰符:默认修饰符,public
状态修饰符:final
抽象修饰符:abstract
用的最多的就是:public
C:修饰成员变量的关键字:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
用的最多的就是:private
D:修饰构造方法的关键字:
权限修饰符:private,默认的,protected,public
用的最多的就是:public
E:修饰成员方法的关键字:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
抽象修饰符:abstract
用的最多的就是:public
F:除此以外的组合规则:
成员变量:public static final
成员方法:public static
public abstract
public final
内部类
- 概述
把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。 - 内部类访问特点
a:内部类可以直接访问外部类的成员,包括私有。
b:外部类要访问内部类的成员,必须创建对象。 - 按照内部类位置分类
成员位置:在成员位置定义的类,被称为成员内部类。 局部位置:在局部位置定义的类,被称为局部内部类。 - 成员内部类
如何在测试类中直接访问内部类的成员。
格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
案例
案例一:
public class MyTest {
public static void main(String[] args) {
//内部类:将一个类定义到,另一个类的内部,那么这个类,就叫做内部类
//举例:例如将 A类定义到B类里面,A类叫做内部类,B类叫做外部类
//根据定义的位置不同,分为成员内部类,和 局部内部类
// 成员内部类:这个内部类,在外部类的成员位置
// 局部内部类:将内部类,定义到外部类的方法中
}
}
class B {
//成员内部类
class A {
}
public void show() {
//局部内部类
class C {
}
}
}
案例二:
public class Outer {
int num = 10;
private int a = 100;
//定义成员内部类
class Inner {
int b = 109;
public void innerShow() {
System.out.println("内部类的show方法");
}
//内部类可以直接访问外部类的成员,包括私有
public void innerTest(){
System.out.println(num);
System.out.println(a);
outerShow();
outerTest();
}
}
public void outerShow() {
System.out.println("这是外部类的show方法");
}
private void outerTest() {
System.out.println("这是外部类的show方法");
}
//外部类,想要访问内部类的成员,得创建内部类的对象
public void method(){
//创建内部类的对象
Inner inner = new Inner();
System.out.println(inner.b);
inner.innerShow();
}
}
public class MyTest {
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.num);
outer.outerShow();
System.out.println("--------------------------------");
//使用成员内部类的属性和方法
//创建成员内部类的语法
Outer.Inner inner=new Outer().new Inner();
System.out.println(inner.b);
inner.innerShow();
System.out.println("---------------");
outer.method();
}
}
案例三:
public class MyTest {
public static void main(String[] args) {
//创建内部类的对象
//内部类被private修饰了,外键就不能直接创建内部类对象了
//Wai.Nei nei = new Wai().new Nei();
Wai wai = new Wai();
wai.waiShow();
}
}
class Wai{
//private 可以修饰内部类
private class Nei{
int num=10;
public void neiShow(){
System.out.println("内部类的show方法");
}
}
public void waiShow(){
Nei nei = new Nei();
System.out.println(nei.num);
nei.neiShow();
}
}
案例四:
public class MyTest {
public static void main(String[] args) {
//内部类被静态修饰后,创建内部类的语法要改变
//静态内部类要访问外部类的成员只能访问静态的
Wai.Nei nei = new Wai.Nei();
}
}
class Wai {
static int num = 10;
private int a = 100;
static class Nei {
public void neiShow() {
System.out.println(num);
waiShow();
}
}
public static void waiShow() {
System.out.println("外部类的show方法");
}
}
案例五:
class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num); //30
System.out.println(Inner.this.num); //20
//System.out.println(new Outer().num); //10
System.out.println(Outer.this.num);//这种写法要注意
}
}
}
案例六:
public class Outer {
int num=10;
private int a=100;
public void waiShow(){
//定义局部内部类
//内部类可以直接访问外部类的成员,包括时私有的
class Inner{
int c=1;
public void neiShow(){
System.out.println(c);
System.out.println(num);
System.out.println(a);
}
}
Inner inner = new Inner();
inner.neiShow();
}
public void waiTest(){
waiShow();
}
}
public class MyTest {
public static void main(String[] args) {
//局部内部类,外界不能直接创建其对象
Outer outer = new Outer();
outer.waiTest();
}
}
- 局部内部类访问局部变量的问题
A: 可以直接访问外部类的成员,包括私有
B: 可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
C:局部内部类访问局部变量必须用final修饰
为什么呢?
因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。
为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。
案例七:
public class MyTest {
public static void main(String[] args) {
// 局部内部类,访问外部类的局部变量,局部变量必须加上final修饰 为什么?
// 因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。
// 为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。
}
}
class Wai {
int b = 100;//成员变量
public void show(final int a) {
//局部变量
final int num = 10;
class Nei {
public void neiShow() {
//局部内部类,访问外部类的局部变量,局部变量必须加上final修饰,JDK1.8 默认就加上了
System.out.println(num);
System.out.println(a);
}
}
}
}
匿名内部类
A:匿名内部类: 就是局部内部类的简化写法。
B:前提: 存在一个类或者接口;这里的类可以是具体类也可以是抽象类。
C:格式:
new 类名或者接口名(){
重写方法;
} ;
D:本质是什么呢?
是一个继承了该类或者实现了该接口的子类匿名对象。
案例
案例一:
public class MyTest {
public static void main(String[] args) {
//匿名内部类:是局部内部类的简写
//匿名内部类,本质上是一个对象,是谁的对象,是实现了该接口或继承了该抽象类的子类对象
//匿名内部类的写法
//AA a = new B();
//a.show();
//C:
//格式:
//new 类名或者接口名() {
// 重写方法;
//};
new AA(){
@Override
public void show() {
System.out.println("重写了show方法");
}
}.show();
}
}
abstract class AA{
public abstract void show();
}
//class B extends AA{
//
// @Override
// public void show() {
// System.out.println("重写了show方法");
// }
//}
案例二:
public class MyTest2 {
public static void main(String[] args) {
MyInterface myInterface=new BB();
myInterface.show();
myInterface.test();
new MyInterface(){
@Override
public void show() {
System.out.println("重写了接口中的show方法");
}
@Override
public void test() {
System.out.println("重写了接口中test方法");
}
}.show();
new MyInterface() {
@Override
public void show() {
System.out.println("重写了接口中的show方法");
}
@Override
public void test() {
System.out.println("重写了接口中test方法");
}
}.test();
//给匿名内部类起个名字
MyInterface my= new MyInterface() {
@Override
public void show() {
System.out.println("重写了接口中的show方法");
}
@Override
public void test() {
System.out.println("重写了接口中test方法");
}
};
//同一个对象,去调用两个方法
my.show();
my.test();
}
}
interface MyInterface{
void show();
void test();
}
//ctrl+I 实现接口中的方法
class BB implements MyInterface{
@Override
public void show() {
System.out.println("重写了接口中的show方法");
}
@Override
public void test() {
System.out.println("重写了接口中的test方法");
}
}
案例三:
public class MyTest {
public static void main(String[] args) {
//匿名内部类可以作为参数传递
set(new MyInterface() {
@Override
public void show() {
System.out.println("重写了show方法");
}
@Override
public void test() {
System.out.println("重写了test方法");
}
});
MyInterface my= new MyInterface() {
@Override
public void show() {
System.out.println("重写了show方法2222");
}
@Override
public void test() {
System.out.println("重写了test方法2222");
}
};
set(my);
}
public static void set(MyInterface myInterface){
myInterface.show();
myInterface.test();
}
}
interface MyInterface{
void show();
void test();
}
//class MyClass implements MyInterface{
//
// @Override
// public void show() {
// System.out.println("重写了show方法");
// }
//
// @Override
// public void test() {
// System.out.println("重写了testfangfa");
// }
//}
案例四:
public class MyTest2 {
public static void main(String[] args) {
//匿名内部类本质上是一个对象,是谁的对象,是实现了该接口 或继承了该抽象类的子类对象。
BB bb = getBB();
bb.show();
}
public static BB getBB(){
BB bb=new BB() {
@Override
public void show() {
System.out.println("afasfdasdfasd");
}
};
return bb;
}
}
abstract class BB{
public abstract void show();
}
//class AA extends BB{
//
// @Override
// public void show() {
// System.out.println("重写了show方法");
// }
//}
面试题:
按照要求,补齐代码
interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
解答:
//接口
interface Inter {
void show();
}
class Outer {
//补代码
public static Inter method(){
Inter in= new Inter() {
@Override
public void show() {
System.out.println("helloworld");
}
};
return in;
}
}
class OuterDemo {
public static void main(String[] args) {
//要求在控制台输出”HelloWorld”
Outer.method().show();
}
}
案例五:
public class MyTest {
public static void main(String[] args) {
//间接方式
Outer outer = new Outer();
outer.waiShow();
//直接方式
new Outer.Inner() {
@Override
public void show() {
System.out.println("重写了接口中的show方法2222");
}
}.show();
Outer.Inner inner= new Outer.Inner() {
@Override
public void show() {
System.out.println("重写了接口中的show方法2222");
}
};
inner.show();
inner.show();
}
}
class Outer{
//成员内部接口
interface Inner{
void show();
}
public void waiShow(){
new Inner(){
@Override
public void show() {
System.out.println("重写了接口中的show方法");
}
}.show();
}
}