Java面向对象
一个很有趣的个人博客,不信你来撩 fangzengye.com
1 继承
- 面向对象编程技术
 - 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
 

1.1 类的继承格式
class 父类 { }
class 子类 extends 父类 {
}
继承例子:
- 公共父类:(写下这一类共同的属性)
 
public class Animal { 
    private String name;  
    private int id; 
    public Animal(String myName, int myid) { 
        name = myName; 
        id = myid;
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}
 
- 企鹅类:
 
public class Penguin extends Animal { 
    public Penguin(String myName, int myid) { 
        super(myName, myid); 
    } 
}
 
- 老鼠类:
 
public class Mouse extends Animal { 
    public Mouse(String myName, int myid) { 
        super(myName, myid); 
    } 
}
 

1.2 继承的特性
-  
子类拥有父类非 private 的属性、方法。
 -  
子类可以对父类进行扩展。
 -  
子类可以用自己的方式实现父类的方法。
 -  
Java 的继承是单继承,但是可以多重继承
 -  
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
 
1.3 继承关键字
1.3.1 extends关键字
extends 只能继承一个类。
public class Animal { private String name; private int id; public Animal(String myName, String myid) { //初始化属性值 } public void eat() { //吃东西方法的具体实现 } public void sleep() { //睡觉方法的具体实现 } }
public class Penguin extends Animal{
}
1.3.2 implements关键字
变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
public interface A { public void eat(); public void sleep(); }public interface B {
public void show();
}
public class C implements A,B {
}
1.3.3 super 与 this 关键字
- super 实现对父类成员的访问,用来引用当前对象的父类。
 - this 指向自己的引用。
 
class Animal { void eat() { System.out.println("animal : eat"); } }class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
结果
animal : eat
dog : eat
animal : eat
 
1.3.4 final关键字
把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写
- 声明类
final class 类名 {//类体} - 声明方法
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体} 
1.4 构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
- 实例
 
class SuperClass { private int n; SuperClass(){ System.out.println("SuperClass()"); } SuperClass(int n) { System.out.println("SuperClass(int n)"); this.n = n; } } // SubClass 类继承 class SubClass extends SuperClass{ private int n;SubClass(){ // 自动调用父类的无参数构造器
System.out.println("SubClass");
}public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
// SubClass2 类继承
class SubClass2 extends SuperClass{
private int n;SubClass2(){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass2");
}
public SubClass2(int n){ // 自动调用父类的无参数构造器
System.out.println("SubClass2(int n):"+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
System.out.println("------SubClass 类继承------");
SubClass sc1 = new SubClass();
SubClass sc2 = new SubClass(100);
System.out.println("------SubClass2 类继承------");
SubClass2 sc3 = new SubClass2();
SubClass2 sc4 = new SubClass2(200);
}
}
- 输出
 
------SubClass 类继承------
SuperClass()
SubClass
SuperClass(int n)
SubClass(int n):100
------SubClass2 类继承------
SuperClass(int n)
SubClass2
SuperClass()
SubClass2(int n):200
 
2 override/overload
子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
- 实例
 
class Animal{ public void move(){ System.out.println("动物可以移动"); } }class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
}public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象a<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 执行 Animal 类的方法</span> b<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//执行 Dog 类的方法</span>
}
}
- 结果
 
动物可以移动
狗可以跑和走
 
- 实例
 
class Animal{ public void move(){ System.out.println("动物可以移动"); } }class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
public void bark(){
System.out.println("狗可以吠叫");
}
}public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象a<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 执行 Animal 类的方法</span> b<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//执行 Dog 类的方法</span> b<span class="token punctuation">.</span><span class="token function">bark</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
}
- 错误
 
TestDog.java:30: cannot find symbol
symbol  : method bark()
location: class Animal
                b.bark();
                 ^
 
- 解释
 
因为b的引用类型Animal没有bark方法。
2.1 方法的重写规则
- 参数列表必须完全与被重写方法的相同。
 - 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类
 - 访问权限不能比父类中被重写的方法的访问权限更低
 - 父类的成员方法只能被它的子类重写。
 - 声明为 final 的方法不能被重写。
 - 声明为 static 的方法不能被重写,但是能够被再次声明。
 - 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
 - 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
 - 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
 - 构造方法不能被重写。
 - 如果不能继承一个方法,则不能重写这个方法。
 
2.2 Super 关键字的使用
需要在子类中调用父类的被重写方法时,要使用 super 关键字。
class Animal{ public void move(){ System.out.println("动物可以移动"); } }class Dog extends Animal{
public void move(){
super.move(); // 应用super类的方法
System.out.println("狗可以跑和走");
}
}public class TestDog{
public static void main(String args[]){Animal b <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Dog 对象</span> b<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//执行 Dog类的方法</span>
}
}
- 输出
 
动物可以移动
狗可以跑和走
 
2.3 重载(Overload)
在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
 最常用的地方就是构造器的重载。
2.3.1 重载规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
 - 被重载的方法可以改变返回类型;
 - 以改变访问修饰符;
 - 可以声明新的或更广的检查异常;
 - 方法能够在同一个类中或者在一个子类中被重载。
 - 无法以返回值类型作为重载函数的区分标准。
 
2.3.2 实例
public class Overloading { public int test(){ System.out.println("test1"); return 1; }<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token keyword">int</span> a<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"test2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//以下两个参数类型顺序不同</span> <span class="token keyword">public</span> String <span class="token function">test</span><span class="token punctuation">(</span><span class="token keyword">int</span> a<span class="token punctuation">,</span>String s<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"test3"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token string">"returntest3"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> String <span class="token function">test</span><span class="token punctuation">(</span>String s<span class="token punctuation">,</span><span class="token keyword">int</span> a<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"test4"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token string">"returntest4"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> Overloading o <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Overloading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>o<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> o<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>o<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token string">"test3"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>o<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"test4"</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
2.4 重写与重载之间的区别
| 区别点 | 重载方法 | 重写方法 | 
|---|---|---|
| 参数列表 | 必须修改 | 一定不能修改 | 
| 返回类型 | 可以修改 | 一定不能修改 | 
| 异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 | 
| 访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) | 
2.5 总结
- 重载(Overloading):定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同
 - 重写(Overriding):存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,
 - 重载:一个类的多态性表现。重写:子类与父类的一种多态性表现。
![在这里插入图片描述]()
![在这里插入图片描述]()
 
3 多态
同一个行为具有多个不同表现形式或形态的能力。
 同一个接口,使用不同的实例而执行不同操作,如图所示:
 
3.1 优点
-  
  
- 消除类型之间的耦合关系
 
 -  
  
- 可替换性
 
 -  
  
- 可扩充性
 
 -  
  
- 接口性
 
 -  
  
- 灵活性
 
 -  
  
- 简化性
 
 
3.2 三个必要条件
- 继承
 - 重写
 - 父类引用指向子类对象
 
public class Test { public static void main(String[] args) { show(new Cat()); // 以 Cat 对象调用 show 方法 show(new Dog()); // 以 Dog 对象调用 show 方法Animal a <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Cat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 向上转型 </span> a<span class="token punctuation">.</span><span class="token function">eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 调用的是 Cat 的 eat</span> Cat c <span class="token operator">=</span> <span class="token punctuation">(</span>Cat<span class="token punctuation">)</span>a<span class="token punctuation">;</span> <span class="token comment">// 向下转型 </span> c<span class="token punctuation">.</span><span class="token function">work</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 调用的是 Cat 的 work</span>}
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">show</span><span class="token punctuation">(</span>Animal a<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> a<span class="token punctuation">.</span><span class="token function">eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 类型判断</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>a <span class="token keyword">instanceof</span> <span class="token class-name">Cat</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 猫做的事情 </span> Cat c <span class="token operator">=</span> <span class="token punctuation">(</span>Cat<span class="token punctuation">)</span>a<span class="token punctuation">;</span> c<span class="token punctuation">.</span><span class="token function">work</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>a <span class="token keyword">instanceof</span> <span class="token class-name">Dog</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 狗做的事情 </span> Dog c <span class="token operator">=</span> <span class="token punctuation">(</span>Dog<span class="token punctuation">)</span>a<span class="token punctuation">;</span> c<span class="token punctuation">.</span><span class="token function">work</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>}
abstract class Animal {
abstract void eat();
}class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
输出
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
 
3.3 虚函数
虚函数的存在是为了多态。
3.3.1 重写
- 例子
 
/* 文件名 : Employee.java */
public class Employee {
   private String name;
   private String address;
   private int number;
   public Employee(String name, String address, int number) {
      System.out.println("Employee 构造函数");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   public void mailCheck() {
      System.out.println("邮寄支票给: " + this.name
       + " " + this.address);
   }
   public String toString() {
      return name + " " + address + " " + number;
   }
   public String getName() {
      return name;
   }
   public String getAddress() {
      return address;
   }
   public void setAddress(String newAddress) {
      address = newAddress;
   }
   public int getNumber() {
     return number;
   }
}
 
假设下面的类继承Employee类:
/* 文件名 : Salary.java */
public class Salary extends Employee
{
   private double salary; // 全年工资
   public Salary(String name, String address, int number, double salary) {
       super(name, address, number);
       setSalary(salary);
   }
   public void mailCheck() {
       System.out.println("Salary 类的 mailCheck 方法 ");
       System.out.println("邮寄支票给:" + getName()
       + " ,工资为:" + salary);
   }
   public double getSalary() {
       return salary;
   }
   public void setSalary(double newSalary) {
       if(newSalary >= 0.0) {
          salary = newSalary;
       }
   }
   public double computePay() {
      System.out.println("计算工资,付给:" + getName());
      return salary/52;
   }
}
 
在我们仔细阅读下面的代码,尝试给出它的输出结果:
/* 文件名 : VirtualDemo.java */
public class VirtualDemo {
   public static void main(String [] args) {
      Salary s = new Salary("员工 A", "北京", 3, 3600.00);
      Employee e = new Salary("员工 B", "上海", 2, 2400.00);
      System.out.println("使用 Salary 的引用调用 mailCheck -- ");
      s.mailCheck();
      System.out.println("\n使用 Employee 的引用调用 mailCheck--");
      e.mailCheck();
    }
}
 
以上实例编译运行结果如下:
Employee 构造函数 Employee 构造函数 使用 Salary 的引用调用 mailCheck -- Salary 类的 mailCheck 方法 邮寄支票给:员工 A ,工资为:3600.0
使用 Employee 的引用调用 mailCheck--
Salary 类的 mailCheck 方法
邮寄支票给:员工 B ,工资为:2400.0
解析
- 实例中,实例化了两个 Salary 对象:一个使用 Salary 引用 s,另一个使用 Employee 引用 e。
 - 当调用 s.mailCheck() 时,编译器在编译时会在 Salary 类中找到 mailCheck(),执行过程 JVM 就调用 Salary 类的 mailCheck()。
 - 因为 e 是 Employee 的引用,所以调用 e 的 mailCheck() 方法时,编译器会去 Employee 类查找 mailCheck() 方法 。
 - 在编译的时候,编译器使用 Employee 类中的 mailCheck() 方法验证该语句, 但是在运行的时候,Java虚拟机(JVM)调用的是 Salary 类中的 mailCheck() 方法。
 
2.4 多态的实现方式
- 重写:
 - 接口
 - 抽象类和抽象方法
 
4 抽象类
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
4.1 抽象类
abstract
/* 文件名 : Employee.java */
public abstract class Employee
{
   private String name;
   private String address;
   private int number;
   public Employee(String name, String address, int number)
   {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   public double computePay()
   {
     System.out.println("Inside Employee computePay");
     return 0.0;
   }
   public void mailCheck()
   {
      System.out.println("Mailing a check to " + this.name
       + " " + this.address);
   }
   public String toString()
   {
      return name + " " + address + " " + number;
   }
   public String getName()
   {
      return name;
   }
   public String getAddress()
   {
      return address;
   }
   public void setAddress(String newAddress)
   {
      address = newAddress;
   }
   public int getNumber()
   {
     return number;
   }
}
 
4.2 继承抽象类
通过一般的方法继承Employee类:
/* 文件名 : Salary.java */
public class Salary extends Employee
{
   private double salary; //Annual salary
   public Salary(String name, String address, int number, double
      salary)
   {
       super(name, address, number);
       setSalary(salary);
   }
   public void mailCheck()
   {
       System.out.println("Within mailCheck of Salary class ");
       System.out.println("Mailing check to " + getName()
       + " with salary " + salary);
   }
   public double getSalary()
   {
       return salary;
   }
   public void setSalary(double newSalary)
   {
       if(newSalary >= 0.0)
       {
          salary = newSalary;
       }
   }
   public double computePay()
   {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}
 
我们不能实例化一个 Employee 类的对象,但是如果我们实例化一个 Salary 类对象,该对象将从 Employee 类继承 7 个成员方法,且通过该方法可以设置或获取三个成员变量。
/* 文件名 : AbstractDemo.java */ public class AbstractDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Call mailCheck using Salary reference --"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> s<span class="token punctuation">.</span><span class="token function">mailCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"\n Call mailCheck using Employee reference--"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> e<span class="token punctuation">.</span><span class="token function">mailCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
结果
Constructing an Employee Constructing an Employee Call mailCheck using Salary reference -- Within mailCheck of Salary class Mailing check to Mohd Mohtashim with salary 3600.0
Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.
4.3 抽象方法
象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
public abstract class Employee { private String name; private String address; private int number;public abstract double computePay();
//其余代码
}
- 如果一个类包含抽象方法,那么该类必须是抽象类。
 - 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
 
4.4 抽象类总结规定
-  
  
- 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
 
 -  
  
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
 
 -  
  
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
 
 -  
  
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
 
 -  
  
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
 
 
5 封装
- 指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
 - 封装可以被认为是一个保护屏障
 - 要访问该类的代码和数据,必须通过严格的接口控制。
 - 主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
 - 适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
 
5.1 封装的优点
-  
  
- 减少耦合。
 
 -  
  
- 类内部的结构可以自由修改。
 
 -  
  
- 可以对成员变量进行更精确的控制。
 
 -  
  
- 隐藏信息,实现细节。
 
 
5.2 实现Java封装的步骤
-  
  
- 修改属性的可见性来限制对属性的访问(一般限制为private)
 
 
public class Person {
    private String name;
    private int age;
}
 
将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
-  
  
- 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问
 
 
public class Person{
    private String name;
    private int age;
    public int getAge(){
      return age;
    }
    public String getName(){
      return name;
    }
    public void setAge(int age){
      this.age = age;
    }
    public void setName(String name){
      this.name = name;
    }
}
 
采用 this 关键字:是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突
5.3 实例
/* 文件名: EncapTest.java */ public class EncapTest{private String name;
private String idNum;
private int age;public int getAge(){
return age;
}public String getName(){
return name;
}public String getIdNum(){
return idNum;
}public void setAge( int newAge){
age = newAge;
}public void setName(String newName){
name = newName;
}
public void setIdNum( String newId){
idNum = newId;
}
}
以上实例中public方法是外部类访问该类成员变量的入口。
 这些方法被称为getter和setter方法。
 通过如下的例子说明EncapTest类的变量怎样被访问:
/* F文件名 : RunEncap.java */ public class RunEncap{ public static void main(String args[]){ EncapTest encap = new EncapTest(); encap.setName("James"); encap.setAge(20); encap.setIdNum("12343ms");System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"Name : "</span> <span class="token operator">+</span> encap<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span> <span class="token string">" Age : "</span><span class="token operator">+</span> encap<span class="token punctuation">.</span><span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
结果
Name : James Age : 20
 
5.4 小结
封装类似把类打包。然后其他调用这个类.方法名
6 接口
- 在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明
 - 类通过继承接口的方式,从而来继承接口的抽象方法。
 - 类描述对象的属性和方法。接口则包含类要实现的方法。
 - 接口无法被实例化,但是可以被实现
 
6.1 接口与类相似点:
- 一个接口可以有多个方法。
 - 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
 - 接口的字节码文件保存在 .class 结尾的文件中。
 - 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
 
6.2 接口与类的区别:
- 接口不能用于实例化对象。
 - 接口没有构造方法。
 - 接口中所有的方法必须是抽象方法。
 - 接口不能包含成员变量,除了 static 和 final 变量。
 - 接口不是被类继承了,而是要被类实现。
 - 接口支持多继承。
 
6.3 接口特性
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
 - 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
 - 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
 
6.4 抽象类和接口的区别
-  
  
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
 
 -  
  
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
 
 -  
  
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
 
 -  
  
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
 
 
6.5 接口的声明
[可见度] interface 接口名称 [extends 其他的接口名] {
        // 声明变量
        // 抽象方法
}
 
例子
/* 文件名 : NameOfInterface.java */ import java.lang.*; //引入包
public interface NameOfInterface
{
//任何类型 final, static 字段
//抽象方法
}
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
 - 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
 - 接口中的方法都是公有的。
 
6.5.1 实例
/* 文件名 : Animal.java */
interface Animal {
   public void eat();
   public void travel();
}
 
6.6 接口的实现
- 当类实现接口的时候,类要实现接口中所有的方法
 - 类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面
 
...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...
 
6.6.1 实例
/* 文件名 : MammalInt.java */ public class MammalInt implements Animal{public void eat(){
System.out.println("Mammal eats");
}public void travel(){
System.out.println("Mammal travels");
}public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
结果
Mammal eats
Mammal travels
 
- 重写接口中声明的方法时,需要注意以下规则:
 
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
 - 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
 - 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
 
- 在实现接口的时候,也要注意一些规则:
 
- 一个类可以同时实现多个接口。
 - 一个类只能继承一个类,但是能实现多个接口。
 - 一个接口能继承另一个接口,这和类之间的继承比较相似。
 
6.7 接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似
// 文件名: Sports.java public interface Sports { public void setHomeTeam(String name); public void setVisitingTeam(String name); }// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
6.8 接口的多继承
-  
在Java中,类的多继承是不合法,但接口允许多继承。
 -  
在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 如下所示:
 
public interface Hockey extends Sports, Event
 
6.9 标记接口
7 包
为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。
7.1 包的作用
-  
1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
 -  
2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
 -  
3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
 
package pkg1[.pkg2[.pkg3…]];
 
package net.java.util;
public class Something{
   ...
}
 
那么它的路径应该是 net/java/util/Something.java 这样保存的。 package(包) 的作用是把不同的 java
程序分类保存,更方便的被其他 java 程序调用。
一个包(package)可以定义为一组相互联系的类型(类、接口、枚举和注释),为这些类型提供访问保护和命名空间管理的功能。
以下是一些 Java 中的包:
- java.lang-打包基础的类
 - java.io-包含输入输出功能的函数
 
7.2 创建包
包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。
7.3 例子
/* 文件名: Animal.java */ package animals;
interface Animal {
public void eat();
public void travel();
}
在同一个包中加入该接口的实现:
package animals;/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{public void eat(){
System.out.println("Mammal eats");
}public void travel(){
System.out.println("Mammal travels");
}public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
7.4 import 关键字
为了能够使用某一个包的成员,我们需要在 Java 程序中明确导入该包。使用 “import” 语句可完成此功能。
import package1[.package2…].(classname|*);
 
7.4.1 例子
package payroll;
public class Boss
{
public void payEmployee(Employee e)
{
e.mailCheck();
}
}
import payroll.*;
 
import payroll.Employee;
 
与Python类似
                    
                

                
            
        
浙公网安备 33010602011771号