日期:2014-05-20  浏览次数:20923 次

J2SE知识点归纳笔记(三)---Java面向对象 Part 2

Java面向对象 Part 2

前言

在上一节中,我们对面向对象进行了

初步的解析,掌握了类和对象的概念

以及定义,实现,在这一节中,我们将对面向对象的灵魂

继承与多态进行剖析,同时也会讲解下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语句向父类构造方法传,那么super(参数)方法要放在第一句 





多态:


多态的分类:


 编译时多态(方法重载)  OverLoading


在同一个类中可以定义多个同名的方法,各个方法的参数表一定不同(参数个数,类型)

返回值可以不同;比如构造方法的重载就是编译时的多态了


代码示例:


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);
	}
}


运行结果:





运行时多态:(方法重定义/覆盖)    OverRidding


运行时多态 = 继承  +  重定义  + 动态绑定


方法覆盖:

子类方法与父类方法名,参数相同,返回值类型也相同;

规律:不能回避比父类方法更多的异常,子类访问控制必须必父类方法更公开


向上转型规则(upcasting)

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()方法




总结:

在这一节中,我们深入面向对象,学习了面向对象的核心部分

继承与多态,并且了解了四种内部类的使用

内容不多,读者写相关代码体现其中的奥秘!


好的,最后谢谢各位读者的支持

如果有什么纰漏,错误,不好的,或者什么好的建议;

望读者指出,不甚感激,(*^__^*) 嘻嘻……!