黑马程序员 Java基础<二>---> 继承、内部类与多态,包
来源:互联网 发布:mac找不到照片宗卷 编辑:程序博客网 时间:2024/05/16 02:55
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
第一节 继承
class Father{int num = 3;void show(){System.out.println(num);}}class Son extends Father{int num = 5;//复写父类函数void show(){System.out.println(num);//this引用,此处省略this,结果是5System.out.println(super.num);//super引用,结果是3.}}class Demo{public static void main(String [] args){Son s = new Son();s.show();}}
在内存中的加载方式:Son中的对象加载之后,才会出现this和super。
class Father{void show(){System.out.println("Wathing TV");}}class Son extends Father{//复写父类函数void show(){System.out.println("Wathing TV");//父类中的功能System.out.println("Playing PC");//扩展的功能}}class Demo{public static void main(String [] args){Son s = new Son();s.show();}}
3、子父类构造函数:子类的构造函数中有一个隐式的构造函数第二节 内部类
先来看一段简单的代码:
//情况一:创建两个常规类A和Bclass A{int a = 5;void fun(){C c = new C();c.method();System.out.println("A:" + a);}//情况二:将C类放入A类中class C{void method(){System.out.println("C访问A:" + a);//可直接访问}}}class B{void fu(){int a = 6;A me = new A();System.out.println("访问A中a:" + me.a);//必须建立对象后才能访问}}class Demo{public static void main(String[] args) {A x = new A();B y = new B();x.fun();y.fu();}}
从代码中就可以看出,内部类的好处。
内部类:将一个类定义在另一个类之中。
一、访问规则(即使用内部类的好处):
1、内部类方法可以访问该类所在的类中作用域的成员,包括私有成员变量。
2、内部类可以对同一个包中的其他类隐藏起来,从而不被访问
3、使用匿名内部类是比较便捷简单的,这种情况较多的用于AWT设计中。
注:为何内部类可直接访问外部类:
由于成员可被对象访问,内部类中持有了一个外部类的引用,,因此就可以直接用:外部类名.this.成员
二、访问格式:
1当内部类定义在外部类的成员位置上,而且非私有,可在外部其他类中直接建立内部类对象
格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象
2、当内部类在成员变量的位置上,可被成员修饰符修饰
·private:将内部类在外部类中进行封装
·static:内部类具备了static的特性,当内部类被static修饰(下面说到的静态内部类),只可访问外部类中的static的成员,访问则受限。
注:(Outer为外部类名,Inner为内部类名,function为非静态成员)
在其他类中,如何访问静态内部类中非静态成员:new Outer.Inner.function();(建立对象访问)
在其他类中,如何访问静态内部类中的静态成员:Outer.Inner.function();(可直接访问)
注意:
1、当内部类中定义了静态成员,该内部类必须为静态的
2、当外部类中静态方法访问内部类时,内部类必须为静态的
3、内部类一般定义为private的,而很少定义为public的。
三、内部类定义原则:------->多在程序设计中使用
1、当描述事物时,事物的内部还有事物,则该事物使用内部类来描述,因为内部事物要使用外部事物内容
举例来说:楼房内部还有家庭住户,家庭住户中还有房间,这就可以用内部类描述。(总不能访问一个住户,就建立一个楼房对象吧,那就可真是有钱人的风范了。)
2、何时定义内部类:
当一个类需要直接访问另一个类中的成员时,则当这个类放入另一个类中,并将内部类封装。
3、内部类生成文件:
我们在编译一个源文件是,如果代码中有内部类,你会发现,生成的class文件中含有例如这样的文件:A$C.class。这是为什么呢?因为内部类是一种编译现象,与虚拟机无关。编译器将会把内部类翻译成用$(美元符号)分隔外部类名和内部类名的常规类文件,而虚拟机对此却一无所知。
四、局部内部类(也称局部类)
看下面一段代码:
class A{private int a = 5;void fun(){class B{//在方法中创建一个内部类void method(){System.out.println("C访问A:" + a);//可直接访问}}B c = new B();//建立一个对象c.method();}}class Demo{public static void main(String[] args) {A x = new A();x.fun();}}
局部内部类:当内部类只在外部类中的某个方法中,创建了这个类型的对象时,且仅使用了一次,那么可在这个方法中定义局部类。
注:
1、局部内部类不可用public或者private访问修饰符声明,它的作用域被限定在了声明这个局部类的代码块中
2、局部类的优势:
a.对外界完全隐藏,即使此方法所在的类也不可访问,也就是说,除此方法外,无任何方法知道它的存在。
b.可访问包含他们的外部类,因还持有外部类的引用;还可访问局部变量,但是局部变量必须被声明为final。
需要注意:局部内部类不可悲成员修饰符修饰,如static
代码如下:
/*局部内部类测试:*/class Outer//类不能用private,但是内部类是可以的{int x = 3;private static class InnerOuter//可在外部类的任意有效的地方,可以用private和static{//......}//含局部变量时void method(final int a)//需访问加final{final int y = 4;//y需要被声明为最终类型,即final才可被局部内部类中的成员访问class Inner//在方法中,相当于局部成员,不能为static或private{void fun()//不能定义静态成员(变量和方法){System.out.println("访问外部类成员变量:+ Outer.this :" + Outer.this.x);System.out.println("局部内部类访问本地变量定义为final:" + y);System.out.println("方法中的参数需定义为final:" + a);}}new Inner().fun();}}class InnerClassDemo0{public static void main(String[] args) {Outer ou = new Outer();ou.method(7);//打印3、4、7ou.method(5);//打印3、4、8}}
说明:为什么定义为final了,还可以改变值7和8;这是因为在传入7后,运行method方法结束后,在栈内存中就会随即消亡,然后就可以再传入8,运行下一个method方法。
五、匿名内部类:
1、匿名内部类:就是内部类的一种简写格式。
当只创建该类的一个对象,可不用再为其命名。所以称之为匿名内部类。代码示例:
class Outer2{int x = 3;public void fun(){/*其中Inner()被改写为AbsDemo(){} (其实就是对父类的复写)*/new AbsDemo()//看这里{void show(){System.out.println("匿名show:" + x);}}.show();//new Inner().show();的简写}}
2、定义前提:
内部类必须继承一个类或实现接口。
但是有一种很特殊,可以不直接继承一个父类,仍可定义一个匿名内部类。因为任何类都是Object的子类。如:
new Object(){ 类中的内容 fun()方法}.fun();
3、格式:
new 父类或接口(参数){定义子类的内容};
4、要点说明:
A.其实匿名内部类就是一个匿名子类对象,可以理解为带有内容的对象。
B.匿名内部类中的方法最好少于3个,方法少,比较方便简单,匿名内部类一定要简化,否则就违背了初衷。
六、静态内部类
1、概述:
上面提到当内部类在成员变量的位置上,可被成员修饰符static修饰,这就是静态内部类
2、使用前提:
某些情况下,会把内部类作为一个隐藏的类,不需要使用内部类引用外部类的对象。因此,可以将外部类声明为static,就可以消除产生的引用。在内部类不需要访问外部类对象的时候,应该使用静态内部类。
下面是示例:
/*静态内部类测试:最大值最小值*/class ArrayAlg{public static class Pair{private double first;private double second;//构造函数获得两个值public Pair(double first,double second){this.first = first;this.second = second;}//访问器:访问私有变量first和secondpublic double getFirst(){return first;}public double getSecond(){return second;}}//定义一个获得最大值和最小值的功能public static Pair minmax(double[] arr){//min和max要分别设置最大和最小,然后才能和数组中的数比较double min = Double.MAX_VALUE;double max = Double.MIN_VALUE;for (int i=0;i<arr.length;i++){if (min > arr[i])min = arr[i];if (max < arr[i])max = arr[i];}return new Pair(min,max);}}class ArrayZDemo{public static void main(String[] args) {double[] d = new double[20];for (int i=0;i<d.length;i++)d[i] = 100*Math.random();ArrayAlg.Pair p = ArrayAlg.minmax(d);System.out.println("min = " + p.getFirst());System.out.println("max = " + p.getSecond());}}
练习:
interface Inter{void method();}class Test{//补足代码,用匿名内部类}class NInnerClassTest{public static void main(String[] args) {Test.function().method();}}
Test.function():类中有一个静态的方法function。
method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象。
--->因为只有是Inter类型的对象,才可以调用method方法。
结果:
interface Inter{void method();}class Test{public static Inter function(){return new Inter(){public void method(){System.out.println("使用静态");}};}}//测试结果class NInnerClassTest{public static void main(String[] args) {Test.function().method();}}
匿名内部类的应用:
class NInnerClassTest{public static void main(String[] args) {show(new Inter(){public void method(){System.out.println("method show run");}});}public static void show(Inter a){a.method();}}
第三节 多态
多态:可理解为事物存在的多种体现形态。又称为动态绑定,是java的核心机制之一。
理解:多态是在运行期间,判断引用实际类型,根据实际类型调用相应的方法。
比如说人又男女之分,动物有猫、狗等之分
一、多态的体现形式:
1、父类的引用指向了自己子类的对象。
2、父类的引用可接收子类的对象。
比如说Person p = new Student();中p指向了Student中的一个对象。如图:
二、多态的前提:
1、必须是类与类之间的关系,如继承和实现关系
2、要存在覆盖的操作,父类中必须由方法被子类覆盖,即重写
3、有父类引用指向子类对象
三、多态的利弊:
1、好处:大大提高了程序的扩展性
2、弊端:虽然提高扩展性,但是只能使用父类的引用访问父类中的成员,不可预先使用子类。这是由于,子类在父类之后加载,此时还没有子类被加载。
在下面的代码中,Animal a = new Cat();是一种“类型提升,向上转型”的过程。如果要实现Cat中的其他Animal没有的功能,那么就需要强制将父类的引用转换成子类类型,然后再调用子类的方法:
Cat c = (Cat) a;c.catchM();
注意:
1、一定不能将父类的对象转换成子类类型。
2、可转换的:父类引用指向自己子类的对象时,该引用可被提升,也可被强制转化。
3、多态自始至终均为子类对象在做变化。
例如
/**分析:1、定义一个动物类这个超类类型(抽象),含有一个吃饭的抽象方法2、定义子类(如猫,狗等),含有自己的方法(猫:抓老鼠;狗:看家)3、用多态实现子类方法*/abstract class Animal //抽象类{abstract void eat();}class Cat extends Animal //Cat继承父类Animal{ //复写父类的抽象方法void eat(){System.out.println("吃鱼");}//定义自身功能void catchM(){System.out.println("抓老鼠");}}class Dog extends Animal{//复写父类的抽象方法void eat(){System.out.println("啃骨头");}//定义自身功能void kanJ(){System.out.println("看家");}}class DuoTaiTest{public static void main(String[] args){Animal a1 = new Cat();//多态运用a2.eat();Dosome(a1);Cat c = (Cat)a1;Dosome(c);c.catchM();Animal a2 = new Dog();a2.eat();Dosome(a2);Dog d = (Dog)a2;Dosome(d);d.kanJ();}public static void Dosome(Animal a){a.eat();}}
四、多态的特点:
1、在多态中成员函数的特点:
·编译时期:参阅引用型变量所属的类中,是否有调用的方法,如果有,则编译通过,若没有,则编译失败。如上面的代码中,引用型变量a是父类Animal的类型,其中有eat 的方法,所以没问题,但是如果调用a.catchM()就会编译失败。
·运行时期:参与对象所属的类中,是否有调用的方法。如引用型变量c是所属于Cat类型的,可以调用c.catchM()
总结:成员函数在多态调用时,编译看左边,运行看右边。子类中局部有变量就访问局部的,没有就访问成员的变量,成员中没有的就在父类中找;如果父类中没有,编译失败。
2、在多态中成员变量(和静态成员)的特点:
·无论编译和运行,都参考左边的,即引用型变量所属的类型。也就是说父类中有自己的变量,则先找父类自己的成员。
·非静态有重写的特点,静态一般不被重写。
原因:因为当调用静态方法时,只要建立子类对象,父类与子类中的静态方法都会随之加载入内存,是不需要调用就可直接用类名.方法名的,而不需要对象。只要引用还存在,就看引用变量的类型。
class Father{int num = 3;void method1(){System.out.println("father-1");}void method2(){System.out.println("father-2");}static void method4(){System.out.println("father-4");}}class Son extends Father{int num = 5;void method1(){System.out.println("son-1");}void method3(){System.out.println("son-3");}static void method4(){System.out.println("son-4");}}class DuotaiYYDemo{public static void main(String[] args) {Father f = new Son();Son s = new Son();f.method1();//son-1s.method1();//son-1f.method2();//father-2s.method3();//son-3//f.method3();报错f.method4();//father-4s.method4();//son-4System.out.println(f.num);//3System.out.println(s.num);//5}}
注:
如果在每次调用方法时都要进行搜索的话,效率是非常低的。因此,JVM虚拟机会预先为每个类在方法区创建一个方法表,列出了所有方法的参数和实际调用的方法。因此,在真正调用的时候,虚拟机只查找这个方法表就可行了。而且,方法区中会有静态方法区和非静态方法区之分(如图)。其中像this和super这两个关键字存在于非静态方法区中,而被static修饰的,存在于静态方法区中。
五、多态的应用
1、定义好工具类,即将共同行为封装在一个类中。
2、对类型进行抽取,---->多态的产生。
3、操作同一个大类型,对其中的小类型均可操作
package cn.conpany.test;public class FatherDemo {//父类受保护方法protected void show(){System.out.println("protected father");}//父类公有方法public void fuc(){System.out.println("public father");}}
package cn.conpany.test.array;public class SonDemo extends cn.conpany.test.FatherDemo{public void showSon(){//自定义方法System.out.println("son show");//调用父类方法show();}}
package cn.conpany.test.object;import cn.conpany.test.FatherDemo;import cn.conpany.test.array.SonDemo;public class PackageDemo {public static void main(String[] args) {//创建子父类对象FatherDemo f = new FatherDemo();SonDemo s = new SonDemo();//类PackageDemo可访问其他类公有方法f.fuc();//public father//访问其他类受保护方法,不可//f.show();//报错s.fuc();//public father//子类可访问父类受保护方法s.showSon();/*son showprotected father*/}}
- 黑马程序员 Java基础<二>---> 继承、内部类与多态,包
- 黑马程序员----继承、内部类与多态,包
- 黑马程序员——java-面向对象二(继承,多态,抽象,接口,包,内部类)
- 黑马程序员--Java基础--继承、抽象类、接口、内部类、异常、包
- 黑马程序员——Java基础---继承,抽象,多态,接口,包,内部类
- Java基础---多态、内部类、包 (黑马程序员)
- 黑马程序员——Java基础:内部类、异常、包
- 黑马程序员--java基础--对象的多态、内部类、匿名内部类、异常处理机制
- 黑马程序员——Java基础---包、内部类、匿名内部类
- 黑马程序员-day08-内部类与包
- 黑马程序员Java基础__内部类与异常
- 黑马程序员——Java基础---内部类与异常
- 黑马程序员--JAVA内部类、异常、包
- 黑马程序员—【Java基础篇】之多态、内部类、异常及包
- 黑马程序员-java基础 内部类
- 黑马程序员:Java基础总结----内部类
- 黑马程序员--Java基础--内部类
- 黑马程序员java基础匿名内部类
- 嵌套for循环
- 黑马程序员_BeanUtils包的使用,主要是BeanUtils和PropertyUtils的区别
- ubuntu下adb不识别小米2
- mybatis下的分页,支持所有的数据库
- 黑马程序员_交通灯管理系统
- 黑马程序员 Java基础<二>---> 继承、内部类与多态,包
- 黑马程序员_银行业务调度系统
- 爱情都被金钱的年代
- 黑马程序员 Java基础<三>---> 抽象类、与接口
- OC中的内存管理—重写dealloc方法
- Objective-c @Class 说明
- OC中的 KVC
- OC KVO
- OC 内存管理