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

一. 封装

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




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值