黑马程序员——Java基础---继承,抽象,多态,接口,包,内部类

-----------android培训java培训、java学习型技术博客、期待与您交流!------------


一、继承

()继承概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

通过extends关键字可以实现类与类的继承

class 子类名 extends 父类名 {}  

单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。

有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。

()继承的好处与弊端

1. 继承的好处:

(1)提高了代码的复用性

多个类相同的成员可以放到同一个类中

(2)提高了代码的维护性

如果功能的代码需要修改,修改一处即可

(3)让类与类之间产生了关系,是多态的前提

其实这也是继承的一个弊端:类的耦合性很强

2. 继承的弊端

(1)耦合性增强,违背了我们的开发原则(高内聚,低耦合)

(2)高内聚:能自己干的事儿从来不求别人

(3)低耦合:类与类直接不要产生太多依赖

()Java中继承的特点

1. 一个类只能有一个父类,不可以有多个父类。

理解:一个儿子只有一个亲爹

举例:

class SubDemo extends Demo{} //true

class SubDemo extends Demo1,Demo2...//error

2. Java支持多层继承(继承体系)

理解:类似家谱

举例:

class A{}

class B extends A{}

class C extends B{}

()注意事项

1. 子类只能继承父类所有非私有的成员(成员方法和成员变量),父类的私有成员,子类不能继承,其实这也体现了继承的另一个弊端:打破了封装性

2. 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。

3. 不要为了部分功能而去继承

4. 我们到底在什么时候使用继承呢?

继承中类之间体现的是:”is a”的关系。

()super关键字

1. super的用法和this很像

this代表本类对应的引用。

super代表父类存储空间的标识(可以理解为父类引用)

2. 用法(thissuper均可如下使用)

访问成员变量

this.成员变量 super.成员变量

访问构造方法(子父类的构造方法问题讲)

this(…) super(…)

访问成员方法(子父类的成员方法问题讲)

this.成员方法() super.成员方法()

案例演示:

class PersonTest{

public static void main(String[] args){

Student s = new Student("子明", 18,"czbk001");

System.out.println(s.name +"--" + s.age +"--"+ s.studyNum);

s.eat();  // 继承来的

s.sleep(); //继承来的

s.study();

Teacher t = new Teacher("凌子峰", 48 ,"czbk008");

System.out.println(t.name +"--" + t.age +"--"+ t.workNum);

t.eat();

t.sleep();

t.work();

}

}

class Person{

String name ;//姓名

int age; //年龄

int money; 

public void eat(){

System.out.println("下雨天 ,吃点热乎的 ");

}

public void sleep(){

System.out.println("下雨天 ,特别适合补一觉,但是我还有事需要做。。。");

}

}

class Student extends Person{

String studyNum; //学号

Student(){}

Student(String name , int age, String studyNum){

this.name = name;

this.age = age;

this.studyNum = studyNum;

}

public void study(){

System.out.println("下雨天 好好学习");

}

}

class Teacher  extends Person{

String workNum; //工号

Teacher(){}

Teacher(String name , int age, String workNum){

this.name = name;

this.age = age;

this.workNum = workNum;

}

public void work(){

System.out.println("下雨天 好好讲课");

}

}

运行结果:

 

()继承中成员变量的关系

成员变量的关系

不同名字:该用谁的就用谁的 

相同名字:

1.子类使用的是子类自己的 

2.子类想使用父类的变量,使用super关键字 

理解: super代表了父类引用 

this:你创建了当前对象,this 是当前对象的引用  

super:你没有创建父类对象,super可以理解为父类的引用,真正代表的是,父类存储空间的标识。

案列演示:

class VarDemo{

public static void main(String[] args){

//创建子类对象 

Zi z = new Zi();

z.show2();

System.out.println();

}

}

class Fu{

int num1 =10;

public void show(){

System.out.println(num1);

}

}

class Zi extends Fu{

int num1=20;

public void show2(){

int num1=30;

System.out.println("num1="+num1);

System.out.println("num1="+this.num1);

System.out.println("num1="+super.num1);

}

}

运行结果:

 

结论:在子类方法中访问一个变量的过程

1. 首先在子类局部范围找

2. 然后在子类成员范围找

3. 最后在父类成员范围找(肯定不能访问到父类局部范围)

4. 如果还是没有就报错。(不考虑父亲的父亲…)

()继承中构造方法的关系

明确:子类不能继承父类的构造方法,但是我们可以调用父类的构造方法

1. 子类中所有的构造方法默认都会访问父类中空参数的构造方法

2. 为什么呢?

因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。

3. 每一个构造方法的第一条语句默认都是:super()

4. 如果父类中没有构造方法,该怎么办呢?

子类通过super去显示调用父类其他的带参的构造方法

子类通过this去调用本类的其他构造方法

本类其他构造也必须首先访问了父类构造

一定要注意:

super(…)或者this(….)必须出现在第一条语句上,并且只能有一个。

否则,就会有父类数据的多次初始化

演示案列:

class Test {

public static void main(String[] args) {

Zi z = new Zi(20);

z.show();

}

}

class Fu{

public int num = 10;

private int num2;

public Fu(int num2 ){

this.num2 = num2;

}

public void show(){

System.out.println("num2="+ num2);

}

}

class Zi extends Fu{

public int num;

public Zi(){

this(0);

System.out.println("zi");

}

public Zi(int num){

    super(num);

this.num = num;

System.out.println("zi");

}

public void show(){

int num = 30;

System.out.println("num="+num);

System.out.println("num="+this.num);

System.out.println("num="+super.num);

super.show();

}

}

运行结果:

 

()继承中成员方法的关系

1. 成员方法的关系:

当方法名不同时,子类可以直接调用父类的方法

相同名字:

(1)子类调用成员方法走的子类的

(2)子类和父类出现了一模一样的方法声明,包括方法名,返回值类型,参数列表,这里,父类的方法被子类的方法重写了

2.演示案例:

class AnimalTest{

public static void main(String[] args){

Cat c = new Cat();

c.sleep();

c.eat();

Dog d = new Dog();

d.sleep();

d.eat();

}

}

class Animal{

String  name;

int leg;

public void sleep(){

System.out.println("晚上睡觉 ");

}

public void eat(){

System.out.println("吃东西,倍儿香");

}

}

 

class Cat extends Animal{

public void sleep(){ 

System.out.println("白天睡觉 ");

}

public void eat(){

System.out.println("吃鱼,倍儿香...");

}

}

class Dog extends Animal{

public void eat(){

System.out.println("吃骨头,倍儿香...");

}

}

运行结果:

 

3. 结论:

通过子类对象去访问一个方法

首先在子类中找

然后在父类中找

如果还是没有就报错。(不考虑父亲的父亲…)

4. 方法重写

(1)方法重写概述:子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。

(2)使用特点:

如果方法名不同,就调用对应的方法

如果方法名相同,最终使用的是子类自己的

(3)方法重写的应用:

当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

(4)方法重写的注意事项

父类中私有方法不能被重写

子类重写父类方法时,访问权限不能低于父类的

父类静态方法,子类也必须通过静态方法进行重写。

5. OverrideOverload的区别?

Override:重写,子父类中,方法名一样,参数列表不同,返回值类型一样 

Overload:重载,同类中,方法名一样,参数列表不同的方法,与返回值类型无关

()final关键字

final关键字是最终的意思,当描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这个值起个名字,以便于阅读。而这个值不需要改变,所以加上final修饰。

final可以修饰类,成员变量,成员方法。

修饰类,类不能被继承

修饰变量,变量就变成了常量,只能被赋值一次

修饰方法,方法不能被重写

final修饰变量的初始化时机

在对象构造完毕前即可(显示初始化)

基本类型被修饰后,是其值不能被改变

引用类型被修饰后,是其地址值不能被改变

简单案例演示:

class FinalDemo{

public static void main(String[] args){

final String s = "192.168.36.72";

System.out.println(s);

final int x = 10;//值不能被改变

System.out.println(x);

final int[] arr = {123,4455};//地址值不能被改变

System.out.println(arr);

}

}

二、抽象类

没有办法具体描述的类,比如:水果,工具,蔬菜,情感……

()格式:

类:abstract class 类名 { }

方法:public abstract void eat();

注意:抽象方法是没有方法体

抽象类中可以没有抽象方法,但是如果有抽象方法,那么此类必然为抽象类

()抽象类特点

1. 抽象类和抽象方法必须用abstract关键字修饰

格式:

类:abstract class 类名 {}

方法:public abstract void eat();

2. 抽象类不一定有抽象方法,可以有非抽象方法,但有抽象方法的类一定是抽象类

3. 抽象类中,有构造方法,但是抽象类不能直接new,也就是不能实例化

4. 那么,抽象类如何实例化呢?

按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。

5. 抽象类的子类

要么是抽象类

要么重写抽象类中的所有抽象方法

()抽象类的成员特点

成员变量

可以是变量

也可以是常量

构造方法

有构造方法,但是不能实例化

那么,构造方法的作用是什么呢?

用于子类访问父类数据的初始化

成员方法

可以有抽象方法,限定子类必须完成某些动作

也可以有非抽象方法,提高代码服用性

()abstract不能和哪些关键字共存

private 冲突 -- 对子类隐藏,无法被复写,而abstract必须让子类重写

final 冲突 -- final修饰后,不能被重写,矛盾

static 无意义 – 类名调用,没有方法体,无意义

()老师案例

具体事物:基础班老师,就业班老师

共性:姓名,年龄,讲课。

class TeacherAbstract{

public static void main(String[] args){

BaseTeacher bt=new BaseTeacher("小李广",28);

System.out.println("我叫"+bt.getName()+",今年"+bt.getAge());

bt.teach();

System.out.println("----------------------------------------");

EmploymentTeacher et=new EmploymentTeacher("凌子峰",29);

System.out.println("我叫"+et.getName()+",今年"+et.getAge());

et.teach();

}

}

abstract class Teacher{

//成员变量

private String name;

private int age;

//构造函数

Teacher(){}

Teacher(String name,int age){

this.name=name;

this.age=age;

}

//get/set

public String getName(){

return name;

}

public void setName(String name){

this.name=name;

}

public int getAge(){

return age;

}

public void setAge(int age){

this.age=age;

}

//抽象方法

public abstract void teach();

}

class BaseTeacher extends Teacher{

BaseTeacher(){}

BaseTeacher(String name,int age){

super(name,age);

}

public void teach(){

System.out.println("我主讲Java_SE course,打好基础好上就业班");

}

}

class EmploymentTeacher extends Teacher{

EmploymentTeacher(){}

EmploymentTeacher(String name,int age){

super(name,age);

}

public void teach(){

System.out.println("我主讲Java_EE course,学好EE好就业");

}

}

运行结果:

 

三、多态

()多态的概述:某一个事物,在不同时刻表现出来的不同状态。

()多态前提和体现

有继承关系

有方法重写

有父类引用指向子类对象

()成员访问特点

成员变量:编译看左边,运行看左边

成员方法:编译看左边,运行看右边

静态方法:编译看左边,运行看左边

()多态的好处和弊端

1. 好处多态的好处

提高了程序的维护性(由继承保证)

提高了程序的扩展性(由多态保证)

2. 多态的弊端

不能访问子类特有功能

那么我们如何才能访问子类的特有功能呢?

多态中的转型

3. 向上转型

从子到父

父类引用指向子类对象

4. 向下转型

强制:从父到子

父类引用转为子类对象

格式:子类 变量名 = (子类类型)父类 变量名;

好处:

转型之前,父类 并不能使用子类的特有功能

转型之后,父类就可以使用子类的功能.

()案例演示:钢铁侠变身过程

class IronManDuoTai{

public static void main(String[] args){

//向上转型,从子类-->父类,父类引用指向子类对象

//使用多态创建对象

Person p=new IronMan();

System.out.println("这是谁?");

//输出属性  ,是父类的

System.out.println("我啊,不认识了吗?"+p.name+"啊!");

System.out.println("怎么做起这个了?");

System.out.print("没办法,只能靠");

//调用方法 是子类的

p.business();

System.out.println("赚点外快了");

//变身过程,向下转型,强制转换,从父类-->子类

System.out.println("前方有情况,救命啊~~~~~~~");

IronMan im=(IronMan)p;

im.fly();

System.out.print("我是"+im.name+",");

im.savePeople();

}

}

//定衣父类Person

class Person{

String name="托尼.斯塔克";

public void business(){

System.out.println("开厂子,很赚钱");

}

}

//定义子类IronMan

class IronMan extends Person{

String name="钢铁侠";

public void business(){

System.out.print("合影5");

}

public void fly(){

System.out.println("飞。。。");

}

public void savePeople(){

System.out.println("我来救人");

}

}

运行结果:

 

四、接口

()接口概述:本质就是一种规则

()作用:就是扩展类功能

()特点:

1. 接口用关键字interface表示

格式:interface 接口名 {}

2. 类实现接口用implements表示

格式:class 类名 implements 接口名 {}

3. 接口不能实例化

4. 那么,接口如何实例化呢?

按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。

5. 接口的子类

要么是抽象类

要么重写接口中的所有抽象方法

6. 接口中可以写方法,但是必须是抽象的.

()接口成员特点

成员变量

只能是常量:默认修饰符 public static final

构造方法

没有,因为接口主要是扩展功能的,而没有具体存在

成员方法

只能是抽象方法:默认修饰符 public abstract

()类与类,类与接口以及接口与接口的关系

类与类

继承关系,只能单继承,但是可以多层继承

类与接口

实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口

接口与接口

继承关系,可以单继承,也可以多继承

()抽象类和接口的区别

成员区别

抽象类:变量,常量;有抽象方法;抽象方法,非抽象方法

接口:常量;抽象方法

关系区别

类与类:继承,单继承

类与接口:实现,单实现,多实现

接口与接口:继承,单继承,多继承

设计理念区别

抽象类:被继承体现的是:”is a”的关系。共性功能

接口:被实现体现的是:”like a”的关系。扩展功能

()教练和运动员案例

乒乓球运动员和篮球运动员。

乒乓球教练和篮球教练。

为了出国交流,跟乒乓球相关的人员都需要学习英语。

class CoachAndPlayer{

public static void main(String[] args){

PPCoach ppc=new PPCoach("刘国梁","棕色",42);

System.out.println("我叫"+ppc.getName()+",今年"+ppc.getAge()+""+",有一双"+ppc.getEyes()+"的眼睛");

ppc.teach();

ppc.eat();

ppc.sleep();

ppc.studyEnglish();

System.out.println("----------------------------");

PPPlayer ppp=new PPPlayer("凌子峰","黑色",20);

System.out.println("我叫"+ppp.getName()+",今年"+ppp.getAge()+""+",有一双"+ppp.getEyes()+"的眼睛");

ppp.play();

ppp.eat();

ppp.sleep();

ppp.studyEnglish();

System.out.println("----------------------------");

BBCoach bbc=new BBCoach("贺子皓","黑色",40);

System.out.println("我叫"+bbc.getName()+",今年"+bbc.getAge()+""+",有一双"+bbc.getEyes()+"的眼睛");

bbc.teach();

bbc.eat();

bbc.sleep();

System.out.println("----------------------------");

BBPlayer bbp=new BBPlayer("韩以风","棕色",21);

System.out.println("我叫"+bbp.getName()+",今年"+bbp.getAge()+""+",有一双"+bbp.getEyes()+"的眼睛");

bbp.play();

bbp.eat();

bbp.sleep();

}

}

abstract class Person{

private String name;

private int age;

private String eyes;

//构造方法

Person(){}

Person(String name,String eyes,int age){

this.name=name;

this.eyes=eyes;

this.age=age;

}

//get/set

public String getName(){

return name;

}

public void setName(String name){

this.name=name;

}

public String getEyes(){

return eyes;

}

public void setEyes(String eyes){

this.eyes=eyes;

}

public int getAge(){

return age;

}

public void setAge(int age){

this.age=age;

}

//成员方法

public void eat(){

System.out.println("吃东西");

}

public abstract void sleep();

}

//教练

abstract class Coach extends Person{

Coach(){}

Coach(String name,String eyes,int age){

super(name,eyes,age);

}

public abstract void teach();

public void sleep(){

System.out.println("教练晚上睡觉");

}

}

//运动员

abstract class Player extends Person{

Player(){}

Player(String name,String eyes,int age){

super(name,eyes,age);

}

public abstract void play();

public void sleep(){

System.out.println("运动员晚上睡觉");

}

}

//接口

interface Study{

public abstract void studyEnglish();

}

//乒乓球教练

class PPCoach extends Coach implements Study{

PPCoach(){}

PPCoach(String name,String eyes,int age){

super(name,eyes,age);

}

public void teach(){

System.out.println("我教乒乓球");

}

public void studyEnglish(){

System.out.println("学英语");

}

}

//篮球教练

class BBCoach extends Coach{

BBCoach(){}

BBCoach(String name,String eyes,int age){

super(name,eyes,age);

}

public void teach(){

System.out.println("我教篮球");

}

}

//乒乓球运动员

class PPPlayer extends Player implements Study{

PPPlayer(){}

PPPlayer(String name,String eyes,int age){

super(name,eyes,age);

}

public void play(){

System.out.println("我会玩乒乓球");

}

public void studyEnglish(){

System.out.println("学英语");

}

}

//篮球运动员

class BBPlayer extends Player{

BBPlayer(){}

BBPlayer(String name,String eyes,int age){

super(name,eyes,age);

}

public void play(){

System.out.println("我会玩篮球");

}

}

运行结果:

 

五、形式参数和返回值问题案例

抽象类作为形式参数,要的是抽象类的子类对象

牌有很多种-- 麻将,三国杀,多米诺骨牌 

所有我们牌定义为抽象类

 

接口作为形式参数,要的是实现了接口的子类对象

牌还有扩展功能 -- 变魔术

class PersonTest{

public static void main(String[] args){

//创建人的对象 

Person p = new Person();

//创建纸牌的对象 

Card c = new Card();

p.play(c);

//父类牌指向子类麻将

Pai pai = new MaJiang();

p.play2(pai);

//变魔术

Magic m = new Card();

p.play3(m);

}

}

class Person{

//人打纸牌的方法 

public void play(Card c){

c. bang();

c.shunzi();

}

//人玩牌

public void play2(Pai p){

p.fun();

}

//人用纸牌变魔术

public void play3(Magic m){

m.moShu();

}

}

//定义接口

interface Magic{

public abstract void moShu();

}

//抽象的牌类 

abstract class Pai{

public abstract void fun();

}

//纸牌继承了牌类实现了Magic接口

class Card extends Pai implements Magic{   

//牌有炸的方法 

public void bang(){

System.out.println("炸了翻倍...");

}

//牌有顺子的方法

public void shunzi(){

System.out.println("顺出去,没了.....");

}

//娱乐

public void fun(){

System.out.println("打牌虽好,不要沉迷哦!!!");

}

//用牌可以变魔术

public void moShu(){

System.out.println("给女神,变魔术.....");

}

}

class MaJiang  extends Pai{

//娱乐

public  void fun(){

System.out.println("打麻将虽好,四圈差不多了");

}

}

运行结果:

 

抽象类作为返回值类型,返回的是抽象类的子类对象 

发牌机不光发纸牌,还能发别的牌(麻将)

class FaPaiJiTest{

public static void main(String[] args){

//创建人对象

Person p = new Person();

//获取发牌机

FaPaiJi fpj = p.getFaPaiJi();

Card c = fpj.faPai();

c.tongHuaShun();

c.fun();

Magic m  =  new Person().getFaPaiJi().faPai3();  //链式编程 

m.moShu();

//new Person().getFaPaiJi().faPai3().moShu();

}

}

class Person{

//人使用 发牌机工作 

public Card work(FaPaiJi fpj ){

Card c = fpj.faPai(); 

return  c ;// Card 

}

//人拿到发牌机 

public FaPaiJi getFaPaiJi(){

return new FaPaiJi();

}

}

class FaPaiJi  {

//发牌机发牌

public Card faPai(){

Card c = new Card();

return c;

}

public Pai faPai2(){

//返回的是抽象类的子类对象 

Pai p = new Card();  //多态

return p;

}

 

public Magic faPai3(){

//返回的是接口的实现类的子类对象 

Magic m = new Card();  //多态  

return m;

}

}

//定义接口

interface Magic{

public abstract void moShu();

}

//定义牌类 

abstract class Pai{

public abstract void fun();

}

//card 继承牌类 ,实现接口 

class Card extends Pai implements Magic{

public void tongHuaShun(){

System.out.println("同花顺.....");

}

public void fun(){

System.out.println("玩牌好好玩~~~");

}

public  void moShu(){

System.out.println("给女神,变魔术.....");

}

}

运行结果:

 

六、包

()包的概述:其实就是文件夹,对类进行分类管理

()包的划分:

举例:

按类划分:

学生类 

增加:create

删除:delete

修改:update

查询:query

老师类

增加:create

删除:delete

修改:update

查询:query

按功能分:

增加:

增加老师,增加学生

删除:

删除老师,删除学生

修改:

修改老师,修改学生

查询:

查询老师,查询学生

()定义包的格式

package 包名;

多级包用.分开即可

注意事项:

package语句必须是程序的第一条可执行的代码

package语句在一个java文件中只能有一个

如果没有package,默认表示无包名

()带包的类的编译和运行

手动式

ajavac编译当前类文件。

b:手动建立包对应的文件夹。

c:a步骤的class文件放到b步骤的最终文件夹下。

d:通过java命令执行。注意了:需要带包名称的执行

java cn.itcast.HelloWorld

自动式

a:javac编译的时候带上-d即可

javac -d . HelloWorld.java

b:通过java命令执行。和手动式一样

()包的作用

1. 为避免多个类重名的情况,如果出现两个相同名字的类,可通过包将两者区分,从而避免冲突。

2. 对类文件进行分类管理,可以将相关的一些类放在同一个包中。

3. 给类提供多层命名空间,如a包中的Demo.class文件,如果要创建Demo对象,就要在使用上加上a.如:a.Demo demo=new a.Demo();

4. 包的出现可以将java的类文件和源文件相分离。

()规则

1. 包必须写在程序的第一行。因为要先有包,才知道类文件的存放地

2. package只有一句,如果不写package,那么默认在当前文件夹

3. 类的全称:包名.类名

4. 编译定义了包的程序文件,在编译时要指定包的存储目录。如:javac d c:\mypack 类名.java

()导包

1. 导包概述:不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。

2. 导包的格式:

import 包名;

注意:

这种方式导入是到类的名称。

虽然可以最后写*,但是不建议。

例如:

import java.util.Scanner;

import java.util.*;

3. packageimportclass的顺序关系

package > import > class

4. 包中的访问

(1)要访问其他包中的类,需要定义类的全称:包名.类名

(2)包如果不在当前路径,需要使用classpath设定环境变量,为JVM指明路径。

(3)被访问的包中的类的权限必须是public

(4)类中的成员权限:public或者protectedprotected是为其他包中的子类提高的一种权限。类共有后,被访问的成员也要共有才可以被访问。不同包中的子类可以直接访问父类中被protected权限修饰的成员。同一包中,protected只作为覆盖。

5. 权限修饰符

 

public

protected

默认

private

同一类中

可以

可以

可以

可以

同一包子类,其他类

可以

可以

可以

不可以

不同包子类

可以

可以

不可以

不可以

不同包子类

可以

不可以

不可以

不可以

注意:一个java文件里面,不能出现两个以上的共有类或者接口。因为被public修饰的类名必须与java文件名相同。

6. 类及其组成可以用的修饰符

(1)类:

默认,publicfinalabstract

我们自己定义:public居多

(2)成员变量:

四种权限修饰符均可,final,static

我们自己定义:private居多

(3)构造方法:

四种权限修饰符均可,其他不可

我们自己定义:public 居多

(4)成员方法:

四种权限修饰符均可,fianl,static,abstract

我们自己定义:public居多

七、内部类

()内部类概述:把类定义在其他类的内部,这个类就被称为内部类。

举例:在类A中定义了一个类B,类B就是内部类。

()内部类的访问特点

1. 内部类可以直接访问外部类的成员,包括私有。

之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this

2. 外部类要访问内部类的成员,必须创建对象。当内部类私有就不能再直接创建内部类对象。

()内部类位置

按照内部类在类中定义的位置不同,可以分为如下两种格式:

成员位置(成员内部类)

局部位置(局部内部类)

1. 成员内部类

(1)外界如何创建对象

外部类名.内部类名 对象名 外部类对象.内部类对象

(2)成员内部的常见修饰符

private 为了保证数据的安全性

static 为了让数据访问更方便

被静态修饰的成员内部类只能访问外部类的静态成员

内部类被静态修饰后的方法

静态方法:直接内部类名.成员方法

非静态方法:创建对象类访问

(3)案例演示

class InnerClass{

public static void main(String[] args){

Outer o=new Outer();

o.display();

System.out.println("------------");

Outer.Inner.show1();

}

}

class Outer{

private int n=1;

static int num=200;

static class Inner{

int n=10;

public void show(){

int n = 120;

System.out.println("n的值为:"+this.n);

System.out.println("n的值为:"+n);

System.out.println("n的值为:"+new Outer().n);

}

public static void show1(){

System.out.println("num的值为:"+num);

}

}

public void display(){

Inner i=new Inner();

i.show();

}

}

运行结果:

 

2. 局部内部类

(1)概述:局部内部类就是方法内部的类

可以直接访问外部类的成员,在方法内部创建内部类的对象,才能使用到内部类的功能。

在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能,

本质:实现了接口(继承类)的子类匿名对象。

(2)局部内部类访问局部变量的注意事项:

必须被final修饰,为什么呢?因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。通过反编译工具可以看一下。

(3)案例演示

class OuterTest{

public static void main(String[] args){

//创建外部类对象

Outer o=new Outer();

o.method();

System.out.println();

}

}

class Outer{

private int num=2;

public void method(){

final int num=6;//注:从内部类中访问本地变量num;需要被声明为最终类型

//局部内部类

class Inner{

public void show(){

System.out.println("num="+num);

System.out.println("num="+new Outer().num);

}

}

//创建内部类对象

Inner i=new Inner();

i.show();

}

}

运行结果:

 

()匿名内部类

1. 就是内部类的简化写法。

2. 前提:存在一个类或者接口

这里的类可以是具体类也可以是抽象类。

3. 格式:

new 类名或者接口名() {重写方法;}

4. 本质:

是一个继承了类或者实现了接口的子类匿名对象

5. 匿名内部类中定义的方法最好不要超过3个。

6. 匿名内部类的利与弊

好处:简化书写

弊端:

①不能直接调用自己的特有方法。

②不能做强转动作

③如果继承的父类或接口中有很多方法时,使用匿名内部类,阅读性会非常差,而且调用会很麻烦。所以匿名内部类中定义的方法一般不超过3个。

案例演示

class AnonymityTest{

public static void main(String[] args){

Anonymity a=new Anonymity();

a.method();

}

}

//存在一个接口Inter

interface Inter{

public abstract void show();

}

class Anonymity{

public void method(){

new Inter(){

//重写方法

public void show(){

System.out.println("HelloWorld...");

}

}.show();

}

}

运行结果:

 

7. 加入方法有多个,如何调用呢?

方式1:每一种格式调用一个,太麻烦

方式2:用类或者接口接收该子类对象,多态思想

案例演示:

class AnonymityTest{

public static void main(String[] args){

Anonymity a=new Anonymity();

a.method();

}

}

//存在一个接口Inter

interface Inter{

public abstract void show();

public abstract void show1();

}

class Anonymity{

public void method(){

Inter i=new Inter(){//接口指向子类对象,多态思想

//重写方法

public void show(){

System.out.println("HelloWorld...");

}

public void show1(){

System.out.println("What?");

}

};

i.show();

i.show1();

}

}

运行结果:

 

8. 接口作为形式参数的案例演示

class PersonTest{

public static void main(String[] args){

PersonStudy ps=new PersonStudy();

ps.show(new Person(){

public void study(){

System.out.println("一起好好学Java~~~~~~");

}

});

System.out.println();

}

}

class PersonStudy{

//接口作为形式参数

public void show(Person p){

p.study();

}

}

interface Person{

public abstract void study();

}

9. 练习题:按照要求,补齐代码

interface Inter { void show(); }

class Outer { //补齐代码 }

class OuterDemo {

     public static void main(String[] args) {

       Outer.method().show();

   }

}

要求在控制台输出”HelloWorld”

分析:

(1)Outer.method(),类名.方法名,说明method是静态方法

(2) method().show(),说明 method返回值类型为对象 

返回的是Inter的实现类的子类匿名对象

实现代码:

class Outer{

public static Inter method(){

return new Inter(){

public void show(){

System.out.println("HelloWorld");

}

};

}

}

 

-----------android培训java培训、java学习型技术博客、期待与您交流!------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值