日期:2014-05-20 浏览次数:20940 次
在上一节中,我们对面向对象进行了
初步的解析,掌握了类和对象的概念
以及定义,实现,在这一节中,我们将对面向对象的灵魂
继承与多态进行剖析,同时也会讲解下4种内部类的使用
好了,废话不多说!
比如:城管,公务员,学生,警察,他们的共性都是人,所以人类是他们的父类,而他们是人类的子类;
子类拥有父类的所有属性,比如姓名,年龄等,同时子类也衍生了一些自己的特性:比如城管拥有暴力执法的属性...
呃,这里说笑而已= =,应该不会给查水表吧
子类 extends 父类
eg: class Student extends Person{}
①Java的数据结构:树形,所以不像C++一样可继承多个父类,只能单继承;Java通过接口和内部类实现多继承
②父类的私有属性也可以继承,但是不可以直接进行访问,只能够通过父类的方法进行访问
③子类如果想调用父类的构造方法要使用super(参数),否则会提示找不到
④Object类是所有类的父类!!
先构造父类的对象,再构造子类对象:
递归构造父类对象,顺序地调用本类成员的赋初值语句,本类的构造方法
代码解析:定义一个父类与子类,跟踪对象的构造顺序,同时在子类中调用父类的方法和重写父类方法
Father.java
package com.jay.example; public class Father { //定义两个私有变量,子类无法直接访问 private String name; private int age; //一个好的编程习惯是写上默认的缺省的构造方法 //在下面的两个构造方法中我们都加入一个println语句 //以此来跟踪构造对象的过程 public Father() { System.out.println("父类无参构造方法被调用"); } public Father(String name,int age) { this.name = name; this.age = age; System.out.println("父类的有参构造方法被调用"); } /*设置这些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 void printMessage() { System.out.println(name + "今年" + age + "岁"); } /* * 这个方法是供子类覆盖重写的 * */ public void test() { System.out.println("我是父类的test"); } }
Son.java
package com.jay.example; public class Son extends Father{ //定义子类自己的属性 private int grade; /* * 同理,为两个构造方法添加println语句用于跟踪构造对象的顺序 * */ Son(){ System.out.println("子类的无参构造方法被调用了"); } Son(String name,int age,int grade){ //通过super关键字调用父类的构造方法,进行参数传递 super(name,age); this.grade = grade; System.out.println("子类的有参构造方法被调用了"); } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } //调用父类的方法访问父类的私有变量 public void printMsg() { System.out.println(getName()+"小学生今年"+getAge()+"岁,读"+ grade + "年级"); } //重写父类的test方法 public void test() { System.out.println("我是子类的test"); } }
ExtendTest.java
package com.jay.example; public class ExtendTest { public static void main(String[] args) { Son son1 = new Son(); son1.setName("大猪"); son1.setAge(25); son1.printMessage(); System.out.println(); Son son2 = new Son("小猪",20,1); son2.printMsg(); System.out.println(); son2.test(); } }
输出结果:
结果分析:
①从上面我们可以知道"先有父亲,后又儿子";创建子类对象时会先创建一个父类对象,
不用我们自己实例化父类对象,系统自动创建;
②我们可以通过super()访问父类构造方法或者用super.XXX访问父类的同名成员
③子类可以重写父类中的方法成员
子类中访问父类的同名成员,用super语句向父类构造方法传,那么super(参数)方法要放在第一句
在同一个类中可以定义多个同名的方法,各个方法的参数表一定不同(参数个数,类型)
返回值可以不同;比如构造方法的重载就是编译时的多态了
代码示例:
package com.jay.example; class HeHe { public HeHe(){} //这里重写几个一样的show方法 public void show() { System.out.println("①重写"); } public void show(int a) { System.out.println("②重写"); } public void show(float a) { System.out.println("③重写"); } public void show(int a,float b) { System.out.println("④重写"); } } public class OverLoadingTest { public static void main(String[] args) { HeHe he = new HeHe(); he.show(); he.show(1); he.show(0.1f); he.show(2, 0.2f); } }
运行结果:
运行时多态 = 继承 + 重定义 + 动态绑定
子类方法与父类方法名,参数相同,返回值类型也相同;
规律:不能回避比父类方法更多的异常,子类访问控制必须必父类方法更公开
Animal a = new dog();
Dog d = (Dog)a;
这里有个问题:
如果调用a的叫方法,jiao()那么,调用的会是Animal的叫还是Dog的叫?
答案是:狗叫,new后面是什么类,动态类型就是什么类
不懂没关系,看下面的演示代码
package com.jay.example; /* * 代码解析: * 在代码中我们定义了三个类,父类,子类以及一个测试类 * 我们要验证的是Father f = new Son(123);当我们调用相同名称的方法时 * 是以父类的方法还是以子类的方法为准 * 从代码可知,我们对print方法进行了重载 * */ class Father { public Father() { System.out.println("父类构造方法打印前\t"); print(); System.out.println("父类构造方法打印后\t"); } public void print() { System.out.println("父类的打印方法\t"); } } class Son extends Father{ int flag; public Son(int flag) { this.flag = flag; System.out.println("子类的构造方法\t"+ this.flag); } public void print() { System.out.println("子类打印方法\t" + flag); } } public class OverRridingTest { public static void main(String[] args) { Father f = new Son(123); } }
运行结果:
分析总结:
从上面的代码,相信大家对运行时的多态有更深一步的了解了;
第二行输出 0 ,说明了调用的是子类的print,这也说明了new后面什么类型,动态类型就是什么类型
内部类有:成员内部类,静态内部类,局部内部类,匿名内部类四种
将一个类嵌套定义在另一个类中,包含内部类的类叫做外部类
内部类可以直接访问外部类的成员和方法
注意:访问内部类的话需要先创建外部类对象,接着才可以用它来创建内部类对象
代码示例:
package com.jay.example; /* * 该代码演示了如何访问内部类,有以下两种方式 * ①在外部类中直接实例化内部类,并且调用内部类的方法或者参数 * ②在测试类中先实例化外部类,在实例化内部类,从而调用对应的方法 * eg:注意是这样写哦!Outer.Inner iner = out1.new Inner(); * */ class Outer { String outString = "外部类的成员变量被访问"; //在该方法中实例化内部类,并且调用show方法 void showinner() { Inner in = new Inner(); in.show(); } //创建一个成员内部类 class Inner { void show() { System.out.println("内部类的show方法被调用!"); System.out.println(outString); } //用于演示在其他类中使用内部类的方法 void test() { System.out.println("在测试类中访问内部类的方法"); } } } public class InnerTest { public static void main(String[] args) { Outer out1 = new Outer(); out1.showinner(); //直接实例化内部类,注意写法! //如果写成Outer.Inner iner = new Outer.Inner();是错的哦! Outer.Inner iner = out1.new Inner(); iner.test(); } }
是成员内部类的一种,但又是特殊的,他具有以下特性:
静态内部类只能够访问外部类的静态成员;
创建内部类对象不需要外部对象,直接:new 外部类名.内部类的构造方法
代码示例:
package com.jay.example; /* * 该代码演示了静态内部类的使用 * 内部类对象只能够访问外部类对象中的静态成员 * 如果调用非静态成员会报错 * 也演示了两种实例化静态内部类成员的办法 * 直接new 外部类.内部类即可 * */ class Draw { public static int k = 250; public void print() { Pen p = new Pen("猪头"); p.speak(); } static class Pen { int i = 100; String name ; public Pen(String name) { this.name = name; } void speak() { System.out.println(name + "你好!\t"+k); } } } public class StaticTest { public static void main(String[] args) { Draw d = new Draw(); d.print(); Draw.Pen pen= new Draw.Pen("呵呵"); pen.speak(); } }
与成员内部类不同,局部内部类是存在于类中的某个局部,可能是在某个方法或者某个块语句中
是用的最少的一种内部类,和局部变量一样,不能够被public,protected,private和static修饰
只能够访问方法中定义的final类型的局部变量
只能够在方法中生成局部内部类的对象并且调用它的方法
实例代码:
package com.jay.example; /* * 该代码演示的是 * 在外部类的方法中创建一个局部内部类 * 同时需要在方法中实例化这个内部类对象 * 而内部类可以访问外部类成员和方法中final修饰的成员变量 * */ class Outer { int a = 1; public void show() { int b = 2; final int c = 3; //定义一个局部内部类 class Inner { public void inPrint() { System.out.println("局部内部类的方法:"); //可以访问外部类中的变量 System.out.println(a); //system.out.printf(b);这里可是会报错的哦! //可以访问方法中的final的变量 System.out.println(c); } } //需要在方法中实例化内部类对象哦! new Inner().inPrint(); } } public class LoaclTest { public static void main(String[] args) { //创建外部类对象,同时调用外部类的方法 Outer out = new Outer(); out.show(); } }
没有名称的内部类,必须是非静态的类
通常是隐式地继承一个父类或者实现一个接口
用的比较多的是作为某个方法的参数,如Java中的GUI事件编程,android中事件处理机制
比较简单,看下下面android中为按钮设置点击事件的方法就了解了
btnregister.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { Intent it = new Intent(LoginActivity.this,RegisterActivity.class); startActivityForResult(it, 0x123); overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); } });
代码实现了为按钮设置一个点击事件,参数,直接是通过new OnClickListener(){}这里实例化一个匿名内部类对象
作为参数,并且重写OnClickListerner接口中的onClick()方法
在这一节中,我们深入面向对象,学习了面向对象的核心部分
继承与多态,并且了解了四种内部类的使用
内容不多,读者写相关代码体现其中的奥秘!
好的,最后谢谢各位读者的支持
如果有什么纰漏,错误,不好的,或者什么好的建议;
望读者指出,不甚感激,(*^__^*) 嘻嘻……!