-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
一、继承
(一)继承概述
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
通过extends关键字可以实现类与类的继承
class子类名extends父类名{}
单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。
(二)继承的好处与弊端
1.继承的好处:
(1)提高了代码的复用性
多个类相同的成员可以放到同一个类中
(2)提高了代码的维护性
如果功能的代码需要修改,修改一处即可
(3)让类与类之间产生了关系,是多态的前提
其实这也是继承的一个弊端:类的耦合性很强
2.继承的弊端
(1)耦合性增强,违背了我们的开发原则(高内聚,低耦合)
(2)高内聚:能自己干的事儿从来不求别人
(3)低耦合:类与类直接不要产生太多依赖
(三)Java中继承的特点
1.一个类只能有一个父类,不可以有多个父类。
理解:一个儿子只有一个亲爹
举例:
classSubDemoextendsDemo{}//true
classSubDemoextendsDemo1,Demo2...//error
2.Java支持多层继承(继承体系)
理解:类似家谱
举例:
classA{}
classBextendsA{}
classCextendsB{}
(四)注意事项
1.子类只能继承父类所有非私有的成员(成员方法和成员变量),父类的私有成员,子类不能继承,其实这也体现了继承的另一个弊端:打破了封装性
2.子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
3.不要为了部分功能而去继承
4.我们到底在什么时候使用继承呢?
继承中类之间体现的是:”isa”的关系。
(五)super关键字
1.super的用法和this很像
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用)
2.用法(this和super均可如下使用)
访问成员变量
this.成员变量 super.成员变量
访问构造方法(子父类的构造方法问题讲)
this(…) super(…)
访问成员方法(子父类的成员方法问题讲)
this.成员方法() super.成员方法()
案例演示:
classPersonTest{
publicstaticvoidmain(String[]args){
Students=newStudent("子明",18,"czbk001");
System.out.println(s.name+"--"+s.age+"--"+s.studyNum);
s.eat();//继承来的
s.sleep();//继承来的
s.study();
Teachert=newTeacher("凌子峰",48,"czbk008");
System.out.println(t.name+"--"+t.age+"--"+t.workNum);
t.eat();
t.sleep();
t.work();
}
}
classPerson{
Stringname;//姓名
intage;//年龄
intmoney;
publicvoideat(){
System.out.println("下雨天,吃点热乎的");
}
publicvoidsleep(){
System.out.println("下雨天,特别适合补一觉,但是我还有事需要做。。。");
}
}
classStudentextendsPerson{
StringstudyNum;//学号
Student(){}
Student(Stringname,intage,StringstudyNum){
this.name=name;
this.age=age;
this.studyNum=studyNum;
}
publicvoidstudy(){
System.out.println("下雨天,好好学习");
}
}
classTeacherextendsPerson{
StringworkNum;//工号
Teacher(){}
Teacher(Stringname,intage,StringworkNum){
this.name=name;
this.age=age;
this.workNum=workNum;
}
publicvoidwork(){
System.out.println("下雨天,好好讲课");
}
}
运行结果:
(六)继承中成员变量的关系
成员变量的关系
不同名字:该用谁的就用谁的
相同名字:
1.子类使用的是子类自己的
2.子类想使用父类的变量,使用super关键字
理解:super代表了父类引用
this:你创建了当前对象,this是当前对象的引用
super:你没有创建父类对象,super可以理解为父类的引用,真正代表的是,父类存储空间的标识。
案列演示:
classVarDemo{
publicstaticvoidmain(String[]args){
//创建子类对象
Ziz=newZi();
z.show2();
System.out.println();
}
}
classFu{
intnum1=10;
publicvoidshow(){
System.out.println(num1);
}
}
classZiextendsFu{
intnum1=20;
publicvoidshow2(){
intnum1=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(….)必须出现在第一条语句上,并且只能有一个。
否则,就会有父类数据的多次初始化
演示案列:
classTest{
publicstaticvoidmain(String[]args){
Ziz=newZi(20);
z.show();
}
}
classFu{
publicintnum=10;
privateintnum2;
publicFu(intnum2){
this.num2=num2;
}
publicvoidshow(){
System.out.println("num2="+num2);
}
}
classZiextendsFu{
publicintnum;
publicZi(){
this(0);
System.out.println("zi");
}
publicZi(intnum){
super(num);
this.num=num;
System.out.println("zi");
}
publicvoidshow(){
intnum=30;
System.out.println("num="+num);
System.out.println("num="+this.num);
System.out.println("num="+super.num);
super.show();
}
}
运行结果:
(八)继承中成员方法的关系
1.成员方法的关系:
当方法名不同时,子类可以直接调用父类的方法
相同名字:
(1)子类调用成员方法走的子类的
(2)子类和父类出现了一模一样的方法声明,包括方法名,返回值类型,参数列表,这里,父类的方法被子类的方法重写了
2.演示案例:
classAnimalTest{
publicstaticvoidmain(String[]args){
Catc=newCat();
c.sleep();
c.eat();
Dogd=newDog();
d.sleep();
d.eat();
}
}
classAnimal{
Stringname;
intleg;
publicvoidsleep(){
System.out.println("晚上睡觉");
}
publicvoideat(){
System.out.println("吃东西,倍儿香");
}
}
classCatextendsAnimal{
publicvoidsleep(){
System.out.println("白天睡觉");
}
publicvoideat(){
System.out.println("吃鱼,倍儿香...");
}
}
classDogextendsAnimal{
publicvoideat(){
System.out.println("吃骨头,倍儿香...");
}
}
运行结果:
3.结论:
通过子类对象去访问一个方法
首先在子类中找
然后在父类中找
如果还是没有就报错。(不考虑父亲的父亲…)
4.方法重写
(1)方法重写概述:子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。
(2)使用特点:
如果方法名不同,就调用对应的方法
如果方法名相同,最终使用的是子类自己的
(3)方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
(4)方法重写的注意事项
父类中私有方法不能被重写
子类重写父类方法时,访问权限不能低于父类的
父类静态方法,子类也必须通过静态方法进行重写。
5.Override和Overload的区别?
Override:重写,子父类中,方法名一样,参数列表不同,返回值类型一样
Overload:重载,同类中,方法名一样,参数列表不同的方法,与返回值类型无关
(九)final关键字
final关键字是最终的意思,当描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这个值起个名字,以便于阅读。而这个值不需要改变,所以加上final修饰。
final可以修饰类,成员变量,成员方法。
修饰类,类不能被继承
修饰变量,变量就变成了常量,只能被赋值一次
修饰方法,方法不能被重写
final修饰变量的初始化时机
在对象构造完毕前即可(显示初始化)
基本类型被修饰后,是其值不能被改变
引用类型被修饰后,是其地址值不能被改变
简单案例演示:
classFinalDemo{
publicstaticvoidmain(String[]args){
finalStrings="192.168.36.72";
System.out.println(s);
finalintx=10;//值不能被改变
System.out.println(x);
finalint[]arr={123,4455};//地址值不能被改变
System.out.println(arr);
}
}
二、抽象类
没有办法具体描述的类,比如:水果,工具,蔬菜,情感……
(一)格式:
类:abstractclass类名{}
方法:publicabstractvoideat();
注意:抽象方法是没有方法体
抽象类中可以没有抽象方法,但是如果有抽象方法,那么此类必然为抽象类
(一)抽象类特点
1.抽象类和抽象方法必须用abstract关键字修饰
格式:
类:abstractclass类名{}
方法:publicabstractvoideat();
2.抽象类不一定有抽象方法,可以有非抽象方法,但有抽象方法的类一定是抽象类
3.抽象类中,有构造方法,但是抽象类不能直接new,也就是不能实例化
4.那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
5.抽象类的子类
要么是抽象类
要么重写抽象类中的所有抽象方法
(三)抽象类的成员特点
成员变量
可以是变量
也可以是常量
构造方法
有构造方法,但是不能实例化
那么,构造方法的作用是什么呢?
用于子类访问父类数据的初始化
成员方法
可以有抽象方法,限定子类必须完成某些动作
也可以有非抽象方法,提高代码服用性
(四)abstract不能和哪些关键字共存
private 冲突--对子类隐藏,无法被复写,而abstract必须让子类重写
final 冲突-- 被final修饰后,不能被重写,矛盾
static 无意义–类名调用,没有方法体,无意义
(五)老师案例
具体事物:基础班老师,就业班老师
共性:姓名,年龄,讲课。
classTeacherAbstract{
publicstaticvoidmain(String[]args){
BaseTeacherbt=newBaseTeacher("小李广",28);
System.out.println("我叫"+bt.getName()+",今年"+bt.getAge());
bt.teach();
System.out.println("----------------------------------------");
EmploymentTeacheret=newEmploymentTeacher("凌子峰",29);
System.out.println("我叫"+et.getName()+",今年"+et.getAge());
et.teach();
}
}
abstractclassTeacher{
//成员变量
privateStringname;
privateintage;
//构造函数
Teacher(){}
Teacher(Stringname,intage){
this.name=name;
this.age=age;
}
//get/set
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
//抽象方法
publicabstractvoidteach();
}
classBaseTeacherextendsTeacher{
BaseTeacher(){}
BaseTeacher(Stringname,intage){
super(name,age);
}
publicvoidteach(){
System.out.println("我主讲Java_SEcourse,打好基础好上就业班");
}
}
classEmploymentTeacherextendsTeacher{
EmploymentTeacher(){}
EmploymentTeacher(Stringname,intage){
super(name,age);
}
publicvoidteach(){
System.out.println("我主讲Java_EEcourse,学好EE好就业");
}
}
运行结果:
三、多态
(一)多态的概述:某一个事物,在不同时刻表现出来的不同状态。
(二)多态前提和体现
有继承关系
有方法重写
有父类引用指向子类对象
(三)成员访问特点
成员变量:编译看左边,运行看左边
成员方法:编译看左边,运行看右边
静态方法:编译看左边,运行看左边
(四)多态的好处和弊端
1.好处多态的好处
提高了程序的维护性(由继承保证)
提高了程序的扩展性(由多态保证)
2.多态的弊端
不能访问子类特有功能
那么我们如何才能访问子类的特有功能呢?
多态中的转型
3.向上转型
从子到父
父类引用指向子类对象
4.向下转型
强制:从父到子
父类引用转为子类对象
格式:子类变量名=(子类类型)父类变量名;
好处:
转型之前,父类p并不能使用子类的特有功能
转型之后,父类就可以使用子类的功能.
(五)案例演示:钢铁侠变身过程
classIronManDuoTai{
publicstaticvoidmain(String[]args){
//向上转型,从子类-->父类,父类引用指向子类对象
//使用多态创建对象
Personp=newIronMan();
System.out.println("这是谁?");
//输出属性,是父类的
System.out.println("我啊,不认识了吗?"+p.name+"啊!");
System.out.println("怎么做起这个了?");
System.out.print("没办法,只能靠");
//调用方法,是子类的
p.business();
System.out.println("赚点外快了");
//变身过程,向下转型,强制转换,从父类-->子类
System.out.println("前方有情况,救命啊~~~~~~~");
IronManim=(IronMan)p;
im.fly();
System.out.print("我是"+im.name+",");
im.savePeople();
}
}
//定衣父类Person
classPerson{
Stringname="托尼.斯塔克";
publicvoidbusiness(){
System.out.println("开厂子,很赚钱");
}
}
//定义子类IronMan
classIronManextendsPerson{
Stringname="钢铁侠";
publicvoidbusiness(){
System.out.print("合影5块");
}
publicvoidfly(){
System.out.println("飞。。。");
}
publicvoidsavePeople(){
System.out.println("我来救人");
}
}
运行结果:
四、接口
(一)接口概述:本质就是一种规则
(二)作用:就是扩展类功能
(三)特点:
1.接口用关键字interface表示
格式:interface接口名{}
2.类实现接口用implements表示
格式:class类名implements接口名{}
3.接口不能实例化
4.那么,接口如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。
5.接口的子类
要么是抽象类
要么重写接口中的所有抽象方法
6.接口中可以写方法,但是必须是抽象的.
(四)接口成员特点
成员变量
只能是常量:默认修饰符publicstaticfinal
构造方法
没有,因为接口主要是扩展功能的,而没有具体存在
成员方法
只能是抽象方法:默认修饰符publicabstract
(五)类与类,类与接口以及接口与接口的关系
类与类
继承关系,只能单继承,但是可以多层继承
类与接口
实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口
接口与接口
继承关系,可以单继承,也可以多继承
(六)抽象类和接口的区别
成员区别
抽象类:变量,常量;有抽象方法;抽象方法,非抽象方法
接口:常量;抽象方法
关系区别
类与类:继承,单继承
类与接口:实现,单实现,多实现
接口与接口:继承,单继承,多继承
设计理念区别
抽象类:被继承体现的是:”isa”的关系。共性功能
接口:被实现体现的是:”likea”的关系。扩展功能
(七)教练和运动员案例
乒乓球运动员和篮球运动员。
乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
classCoachAndPlayer{
publicstaticvoidmain(String[]args){
PPCoachppc=newPPCoach("刘国梁","棕色",42);
System.out.println("我叫"+ppc.getName()+",今年"+ppc.getAge()+"岁"+",有一双"+ppc.getEyes()+"的眼睛");
ppc.teach();
ppc.eat();
ppc.sleep();
ppc.studyEnglish();
System.out.println("----------------------------");
PPPlayerppp=newPPPlayer("凌子峰","黑色",20);
System.out.println("我叫"+ppp.getName()+",今年"+ppp.getAge()+"岁"+",有一双"+ppp.getEyes()+"的眼睛");
ppp.play();
ppp.eat();
ppp.sleep();
ppp.studyEnglish();
System.out.println("----------------------------");
BBCoachbbc=newBBCoach("贺子皓","黑色",40);
System.out.println("我叫"+bbc.getName()+",今年"+bbc.getAge()+"岁"+",有一双"+bbc.getEyes()+"的眼睛");
bbc.teach();
bbc.eat();
bbc.sleep();
System.out.println("----------------------------");
BBPlayerbbp=newBBPlayer("韩以风","棕色",21);
System.out.println("我叫"+bbp.getName()+",今年"+bbp.getAge()+"岁"+",有一双"+bbp.getEyes()+"的眼睛");
bbp.play();
bbp.eat();
bbp.sleep();
}
}
abstractclassPerson{
privateStringname;
privateintage;
privateStringeyes;
//构造方法
Person(){}
Person(Stringname,Stringeyes,intage){
this.name=name;
this.eyes=eyes;
this.age=age;
}
//get/set
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetEyes(){
returneyes;
}
publicvoidsetEyes(Stringeyes){
this.eyes=eyes;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
//成员方法
publicvoideat(){
System.out.println("吃东西");
}
publicabstractvoidsleep();
}
//教练
abstractclassCoachextendsPerson{
Coach(){}
Coach(Stringname,Stringeyes,intage){
super(name,eyes,age);
}
publicabstractvoidteach();
publicvoidsleep(){
System.out.println("教练晚上睡觉");
}
}
//运动员
abstractclassPlayerextendsPerson{
Player(){}
Player(Stringname,Stringeyes,intage){
super(name,eyes,age);
}
publicabstractvoidplay();
publicvoidsleep(){
System.out.println("运动员晚上睡觉");
}
}
//接口
interfaceStudy{
publicabstractvoidstudyEnglish();
}
//乒乓球教练
classPPCoachextendsCoachimplementsStudy{
PPCoach(){}
PPCoach(Stringname,Stringeyes,intage){
super(name,eyes,age);
}
publicvoidteach(){
System.out.println("我教乒乓球");
}
publicvoidstudyEnglish(){
System.out.println("学英语");
}
}
//篮球教练
classBBCoachextendsCoach{
BBCoach(){}
BBCoach(Stringname,Stringeyes,intage){
super(name,eyes,age);
}
publicvoidteach(){
System.out.println("我教篮球");
}
}
//乒乓球运动员
classPPPlayerextendsPlayerimplementsStudy{
PPPlayer(){}
PPPlayer(Stringname,Stringeyes,intage){
super(name,eyes,age);
}
publicvoidplay(){
System.out.println("我会玩乒乓球");
}
publicvoidstudyEnglish(){
System.out.println("学英语");
}
}
//篮球运动员
classBBPlayerextendsPlayer{
BBPlayer(){}
BBPlayer(Stringname,Stringeyes,intage){
super(name,eyes,age);
}
publicvoidplay(){
System.out.println("我会玩篮球");
}
}
运行结果:
五、形式参数和返回值问题案例
抽象类作为形式参数,要的是抽象类的子类对象
牌有很多种--麻将,三国杀,多米诺骨牌
所有我们牌定义为抽象类
接口作为形式参数,要的是实现了接口的子类对象
牌还有扩展功能--变魔术
classPersonTest{
publicstaticvoidmain(String[]args){
//创建人的对象
Personp=newPerson();
//创建纸牌的对象
Cardc=newCard();
p.play(c);
//父类牌指向子类麻将
Paipai=newMaJiang();
p.play2(pai);
//变魔术
Magicm=newCard();
p.play3(m);
}
}
classPerson{
//人打纸牌的方法
publicvoidplay(Cardc){
c.bang();
c.shunzi();
}
//人玩牌
publicvoidplay2(Paip){
p.fun();
}
//人用纸牌变魔术
publicvoidplay3(Magicm){
m.moShu();
}
}
//定义接口
interfaceMagic{
publicabstractvoidmoShu();
}
//抽象的牌类
abstractclassPai{
publicabstractvoidfun();
}
//纸牌继承了牌类,实现了Magic接口
classCardextendsPaiimplementsMagic{
//牌有炸的方法
publicvoidbang(){
System.out.println("炸了,翻倍...");
}
//牌有顺子的方法
publicvoidshunzi(){
System.out.println("顺出去,没了.....");
}
//娱乐
publicvoidfun(){
System.out.println("打牌虽好,不要沉迷哦!!!");
}
//用牌可以变魔术
publicvoidmoShu(){
System.out.println("给女神,变魔术.....");
}
}
classMaJiangextendsPai{
//娱乐
publicvoidfun(){
System.out.println("打麻将虽好,四圈差不多了");
}
}
运行结果:
抽象类作为返回值类型,返回的是抽象类的子类对象
发牌机不光发纸牌,还能发别的牌(麻将)
classFaPaiJiTest{
publicstaticvoidmain(String[]args){
//创建人对象
Personp=newPerson();
//获取发牌机
FaPaiJifpj=p.getFaPaiJi();
Cardc=fpj.faPai();
c.tongHuaShun();
c.fun();
Magicm=newPerson().getFaPaiJi().faPai3();//链式编程
m.moShu();
//newPerson().getFaPaiJi().faPai3().moShu();
}
}
classPerson{
//人使用发牌机工作
publicCardwork(FaPaiJifpj){
Cardc=fpj.faPai();
returnc;//Card
}
//人拿到发牌机
publicFaPaiJigetFaPaiJi(){
returnnewFaPaiJi();
}
}
classFaPaiJi{
//发牌机发牌
publicCardfaPai(){
Cardc=newCard();
returnc;
}
publicPaifaPai2(){
//返回的是抽象类的子类对象
Paip=newCard();//多态
returnp;
}
publicMagicfaPai3(){
//返回的是接口的实现类的子类对象
Magicm=newCard();//多态
returnm;
}
}
//定义接口
interfaceMagic{
publicabstractvoidmoShu();
}
//定义牌类
abstractclassPai{
publicabstractvoidfun();
}
//card继承牌类,实现接口
classCardextendsPaiimplementsMagic{
publicvoidtongHuaShun(){
System.out.println("同花顺.....");
}
publicvoidfun(){
System.out.println("玩牌好好玩~~~");
}
publicvoidmoShu(){
System.out.println("给女神,变魔术.....");
}
}
运行结果:
六、包
(一)包的概述:其实就是文件夹,对类进行分类管理
(二)包的划分:
举例:
按类划分:
学生类
增加:create
删除:delete
修改:update
查询:query
老师类
增加:create
删除:delete
修改:update
查询:query
按功能分:
增加:
增加老师,增加学生
删除:
删除老师,删除学生
修改:
修改老师,修改学生
查询:
查询老师,查询学生
(三)定义包的格式
package包名;
多级包用.分开即可
注意事项:
package语句必须是程序的第一条可执行的代码
package语句在一个java文件中只能有一个
如果没有package,默认表示无包名
(四)带包的类的编译和运行
手动式
a:javac编译当前类文件。
b:手动建立包对应的文件夹。
c:把a步骤的class文件放到b步骤的最终文件夹下。
d:通过java命令执行。注意了:需要带包名称的执行
javacn.itcast.HelloWorld
自动式
a:javac编译的时候带上-d即可
javac-d.HelloWorld.java
b:通过java命令执行。和手动式一样
(五)包的作用
1.为避免多个类重名的情况,如果出现两个相同名字的类,可通过包将两者区分,从而避免冲突。
2.对类文件进行分类管理,可以将相关的一些类放在同一个包中。
3.给类提供多层命名空间,如a包中的Demo.class文件,如果要创建Demo对象,就要在使用上加上a.如:a.Demodemo=newa.Demo();
4.包的出现可以将java的类文件和源文件相分离。
(六)规则
1.包必须写在程序的第一行。因为要先有包,才知道类文件的存放地
2.package只有一句,如果不写package,那么默认在当前文件夹
3.类的全称:包名.类名
4.编译定义了包的程序文件,在编译时要指定包的存储目录。如:javac—dc:\mypack类名.java。
(七)导包
1.导包概述:不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。
2.导包的格式:
import包名;
注意:
这种方式导入是到类的名称。
虽然可以最后写*,但是不建议。
例如:
importjava.util.Scanner;
importjava.util.*;
3.package,import,class的顺序关系
package>import>class
4.包中的访问
(1)要访问其他包中的类,需要定义类的全称:包名.类名
(2)包如果不在当前路径,需要使用classpath设定环境变量,为JVM指明路径。
(3)被访问的包中的类的权限必须是public。
(4)类中的成员权限:public或者protected,protected是为其他包中的子类提高的一种权限。类共有后,被访问的成员也要共有才可以被访问。不同包中的子类可以直接访问父类中被protected权限修饰的成员。同一包中,protected只作为覆盖。
5.权限修饰符
注意:一个java文件里面,不能出现两个以上的共有类或者接口。因为被public修饰的类名必须与java文件名相同。
6.类及其组成可以用的修饰符
(1)类:
默认,public,final,abstract
我们自己定义:public居多
(2)成员变量:
四种权限修饰符均可,final,static
我们自己定义:private居多
(3)构造方法:
四种权限修饰符均可,其他不可
我们自己定义:public居多
(4)成员方法:
四种权限修饰符均可,fianl,static,abstract
我们自己定义:public居多
七、内部类
(一)内部类概述:把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。
(二)内部类的访问特点
1.内部类可以直接访问外部类的成员,包括私有。
之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this。
2.外部类要访问内部类的成员,必须创建对象。当内部类私有就不能再直接创建内部类对象。
(三)内部类位置
按照内部类在类中定义的位置不同,可以分为如下两种格式:
成员位置(成员内部类)
局部位置(局部内部类)
1.成员内部类
(1)外界如何创建对象
外部类名.内部类名对象名=外部类对象.内部类对象
(2)成员内部的常见修饰符
private为了保证数据的安全性
static为了让数据访问更方便
被静态修饰的成员内部类只能访问外部类的静态成员
内部类被静态修饰后的方法
静态方法:直接内部类名.成员方法
非静态方法:创建对象类访问
(3)案例演示
classInnerClass{
publicstaticvoidmain(String[]args){
Outero=newOuter();
o.display();
System.out.println("------------");
Outer.Inner.show1();
}
}
classOuter{
privateintn=1;
staticintnum=200;
staticclassInner{
intn=10;
publicvoidshow(){
intn=120;
System.out.println("n的值为:"+this.n);
System.out.println("n的值为:"+n);
System.out.println("n的值为:"+newOuter().n);
}
publicstaticvoidshow1(){
System.out.println("num的值为:"+num);
}
}
publicvoiddisplay(){
Inneri=newInner();
i.show();
}
}
运行结果:
2.局部内部类
(1)概述:局部内部类就是方法内部的类
可以直接访问外部类的成员,在方法内部创建内部类的对象,才能使用到内部类的功能。
在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能,
本质:实现了接口(继承类)的子类匿名对象。
(2)局部内部类访问局部变量的注意事项:
必须被final修饰,为什么呢?因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。通过反编译工具可以看一下。
(3)案例演示
classOuterTest{
publicstaticvoidmain(String[]args){
//创建外部类对象
Outero=newOuter();
o.method();
System.out.println();
}
}
classOuter{
privateintnum=2;
publicvoidmethod(){
finalintnum=6;//注:从内部类中访问本地变量num;需要被声明为最终类型
//局部内部类
classInner{
publicvoidshow(){
System.out.println("num="+num);
System.out.println("num="+newOuter().num);
}
}
//创建内部类对象
Inneri=newInner();
i.show();
}
}
运行结果:
(四)匿名内部类
1.就是内部类的简化写法。
2.前提:存在一个类或者接口
这里的类可以是具体类也可以是抽象类。
3.格式:
new类名或者接口名(){重写方法;}
4.本质:
是一个继承了类或者实现了接口的子类匿名对象
5.匿名内部类中定义的方法最好不要超过3个。
6.匿名内部类的利与弊
好处:简化书写
弊端:
①不能直接调用自己的特有方法。
②不能做强转动作
③如果继承的父类或接口中有很多方法时,使用匿名内部类,阅读性会非常差,而且调用会很麻烦。所以匿名内部类中定义的方法一般不超过3个。
案例演示
classAnonymityTest{
publicstaticvoidmain(String[]args){
Anonymitya=newAnonymity();
a.method();
}
}
//存在一个接口Inter
interfaceInter{
publicabstractvoidshow();
}
classAnonymity{
publicvoidmethod(){
newInter(){
//重写方法
publicvoidshow(){
System.out.println("HelloWorld...");
}
}.show();
}
}
运行结果:
7.加入方法有多个,如何调用呢?
方式1:每一种格式调用一个,太麻烦
方式2:用类或者接口接收该子类对象,多态思想
案例演示:
classAnonymityTest{
publicstaticvoidmain(String[]args){
Anonymitya=newAnonymity();
a.method();
}
}
//存在一个接口Inter
interfaceInter{
publicabstractvoidshow();
publicabstractvoidshow1();
}
classAnonymity{
publicvoidmethod(){
Interi=newInter(){//接口指向子类对象,多态思想
//重写方法
publicvoidshow(){
System.out.println("HelloWorld...");
}
publicvoidshow1(){
System.out.println("What?");
}
};
i.show();
i.show1();
}
}
运行结果:
8.接口作为形式参数的案例演示
classPersonTest{
publicstaticvoidmain(String[]args){
PersonStudyps=newPersonStudy();
ps.show(newPerson(){
publicvoidstudy(){
System.out.println("一起好好学Java~~~~~~");
}
});
System.out.println();
}
}
classPersonStudy{
//接口作为形式参数
publicvoidshow(Personp){
p.study();
}
}
interfacePerson{
publicabstractvoidstudy();
}
9.练习题:按照要求,补齐代码
interfaceInter{voidshow();}
classOuter{//补齐代码}
classOuterDemo{
publicstaticvoidmain(String[]args){
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
分析:
(1)Outer.method(),类名.方法名,说明method是静态方法
(2)method().show(),说明method返回值类型为对象
返回的是Inter的实现类的子类匿名对象
实现代码:
classOuter{
publicstaticIntermethod(){
returnnewInter(){
publicvoidshow(){
System.out.println("HelloWorld");
}
};
}
}
-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
1200字范文,内容丰富有趣,写作的好帮手!