您的位置:首页 > 编程语言 > Java开发

Java笔记----5. 面向对象(封装、继承、多态)

2015-03-04 21:41 363 查看
一. 封装

封装,是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。

1. 访问控件符

private:
当前类访问权限,如果类里的一个成员使用private来修饰,则这个成员只能在当前类的内部被访问。显然这个修饰符用于Field最合适,可以把Field隐藏在该类内部。

default(不使用任何修饰符):包访问权限,default修饰的成员或外部类可以被相同包下的其他类访问。

protected:子类访问权限,如果类里的一个成员使用protected来修饰,那么这个成员既可以被同一包中的其他类访问,也可以被不同包中的子类访问。通常使用这个修饰符是希望其子类来重写这个方法。

public:公共访问权限,被public修饰的成员可以被所有类访问,不管访问类和被访问类是否处于同一个包中,是否具有父子继承关系。

2. package,import和import static

java允许将一组功能相关的类放在同一个package下,从而组成逻辑上的类库单元,相当于命名空间。

如查希望把一个类放在指定的包结构下,我们应该在java源程序的第一个非注释行放置如下格式的代码:

package packageName;
一旦在java源文件中使用了这个package语句,就意味着该源文件里定义的所有类都属于这个包。
编译:

javac -d . Hello.java
则会生成一个packageName的文件夹,在文件夹里则有一个Hello.class文件
执行:进入packName文件夹,要执行
java packName.Hello

同一个包下的类可以自由访问,不同包下的类必须用命名
Hello h = new Hello();
lee.sub.Apple a = new lee.sub.Apple(); //全名


import 可以向某个java文件中导入指定包层次个某个类或全部类

//导入单个类
import package.subpackage...ClassName;
import lee.sub.Apple;

//导入全部类
import package.subpackage...*
import lee.* //表明导入lee包下所有类,但是lee包下sub子包内的类不会被导入
import lee.sub.* //才能导入

一旦导入指定的类,则在源文件中使用这些类时就可以省略包前缀,不再而要使用类全名了。

import static 语句用于导入指定类的某个或全部静态Field、方法。
import static package.subpackage...ClassName.fieldName | methodName;
import static package.subpackage...ClassName.*;


二. 继承

java的继承具有单继承的特点,也就是每个子类只有一个直接父类。

java的继承通过extends关键字来实现。

修饰符 class SubClass extends SuperClass

{

//类定义部分

}
1. 重写父类的方法

public class Bird
{
 public void fly()
 {
  System.out.println("天上飞的鸟");
 }
}

public class Ostrich extends Bird
{
 //重写Bird类的fly方法
 public void fly()
 {
  System.out.println("地上跑的鸟");
 }
 
 public static void main(String[] args)
 {
  Ostrich os = new Ostrich();
  os.fly();//将输出"地上跑的鸟"
 }
}

a. 方法的重写要求方法名相同、形参列表相同。

b. 覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。

c. 如果需要在子类方法中调用父类中被覆盖的方法,则可以使用super(被覆盖的是实例方法)或者父类名(被覆盖的是类方法)作为调用者来调用父类中被覆盖的方法。

d. 如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此子类无法访问该方法,也就是无法重写该方法。如果子类中定义了一个与父类private方法相同的方法名,则他依然不是重写,只是在子类中重新定义的一个新方法。

class BaseClass
{
 //private方法,子类不能访问
 private void test();
}

class SubClass extends BaseClass
{
 //此处不是方法重写,是子类的一个新方法,所以可以增加static关系字
 public static void test();
}


2. super限定

如果需要在子类方法中调用父类中被覆盖的方法,则可以使用super限定来调用父类被覆盖的实例方法。

super也不能出现在static修饰的方法中。
public class Ostrich extends Bird
{
 public void callOverridedMethod()
 {
  //在子类方法中显示调用父类被覆盖的实例方法
  supre.fly();
 }
 
 //重写Bird类的fly方法
 public void fly()
 {
  System.out.println("地上跑的鸟");
 }
 
 public static void main(String[] args)
 {
  Ostrich os = new Ostrich();
  os.fly();//将输出"地上跑的鸟"
 }
}


三. 多态

1. 多态性

java引用变量有两个类型:一个是编译时类型,一个是运行时类型。

编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。

如果编译时类型和运行时类型不一致,就可能出现所谓的多态。

class BaseClass
{
 public int book = 6;
 
 public void base()
 {
  System.out.println("父类的普通方法");
 }
 
 public void test()
 {
  System.out.println("父类的被覆盖的方法");
 }
}

public class SubClass extends BaseClass
{
 //重新定义一个book实例变量隐藏父类的book实例变量
 public String book = "轻量级Java EE企业应用实战";
 
 public void sub()
 {
  System.out.println("子类的普通方法");
 }
 
 public void test()
 {
  System.out.println("子类的覆盖父类的方法");
 }
 
 public static void main(String[] args)
 {
  // 下面编译时类型和运行时类型完全一样,因此不存在多态
  BaseClass bc = new BaseClass();
  System.out.println(bc.book);// 输出 6
  
  // 下面两次调用将执行BaseClass的方法
  bc.base();
  bc.test();
  
  // 下面编译时类型和运行时类型完全一样,因此不存在多态
  SubClass sc = new SubClass();
  System.out.println(sc.book);// 输出"轻量级Java EE企业应用实战"
  
  // 下面调用将执行从父类继承到的base()方法
  sc.base();
  // 下面调用将执行从当前类的test()方法
  sc.test();
  
  
  // 下面编译时类型和运行时类型不一样,多态发生
  BaseClass ploymophicBc = new SubClass();
  System.out.println(ploymophicBc.book);// 输出6 —— 表明访问的是父类对象的实例变量
  
  // 下面调用将执行从父类继承到的base()方法
  ploymophicBc.base();
  // 下面调用将执行从当前类的test()方法
  ploymophicBc.test();
  
  // 因为ploymophicBc的编译类型是BaseClass,
  // BaseClass类没有提供sub方法,所以下面代码编译时会出现错误。
  // ploymophicBc.sub();
 }
}

a. ploymophicBc 的编译类型是BaseClass,而运行时类型是SubClass,当运行其方法时,总是表现为子类方法的行为。

b. 因为ploymophicBc 编译时类型为BaseClass,因此编译时无法调用sub()方法。

c. 与方法不同的是,对象的Field则不具备多态性。上面ploymophicBc.book只是输出BaseClass的实例Field,也就是编译时所定义的。

2. 引用变量强制类型转换

a. 基本类型之间的转换只能在数值类型之间进行,数值和布尔类型之间不能进行类型转换。

b. 引用类型之间的转换只能在具有继承关系的两个类型之间进行,如果试图把一个父类实例转换成子类类型,则这个对象必须实际上是子类实例才行。

public class ConversionTest
{
 public static void main(String[] args)
 {
  double d = 13.4;
  long l = (long)d;
  System.out.println(l);
  
  int in = 5;
  // 试图把一个数值类型的变量转换为boolean类型,下面代码编译出错
  // 编译时候会提示: 不可转换的类型
  // boolean b = (boolean)in;
  
  Object obj = "Hello";
  // obj变量的编译类型为Object,Object与String存在继承关系,可以强制类型转换
  // 而且obj变量实际上类型是String类型,所以运行时也可通过
  String objStr = (String)obj;
  System.out.println(objStr);
  
  // 定义一个objPri变量,编译类型为Object,实际类型为Integer
  Object objPri = new Integer(5);
  // objPri变量的编译时类型为Object,objPri的运行时类型为Integer,Object与Integer存在继承关系
  // 可以强制类型转换,
  
  // 而objPri变量实际上类型是Integer类型,所以下面代码运行时引发ClassCastException异常
  String str = (String)objPri;
 }
}


3. instanceof运算符

强制类型转换时可能出现异常,因此进行类型转换前先通过instanceof 来判断是否可以成功转换。

它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是返回true。
// 声明hello时使用Object类,则hello的编译类型是Object,
// Object是所有类的父类, 但hello变量的实际类型是String
Object hello = "Hello";

// String与Object类存在继承关系,可以进行instanceof运算。返回true。
System.out.println("字符串是否是Object类的实例:" + (hello instanceof Object));

System.out.println("字符串是否是String类的实例:" + (hello instanceof String)); // 返回true。

// Math与Object类存在继承关系,可以进行instanceof运算。返回false。
System.out.println("字符串是否是Math类的实例:" + (hello instanceof Math));

// String实现了Comparable接口,所以返回true。
System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable));

String a = "Hello";
// String类与Math类没有继承关系,所以下面代码编译无法通过
// System.out.println("字符串是否是Math类的实例:" + (a instanceof Math));





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐