Java第七章总结

7.1类的封装


封装将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。例如:一台计算机内部极其复杂,有主板、CPU、硬盘和内存, 而一般用户不需要了解它的内部细节,不需要知道主板的型号、CPU 主频、硬盘和内存的大小,于是计算机制造商将用机箱把计算机封装起来,对外提供了一些接口,如鼠标、键盘和显示器等,这样当用户使用计算机就非常方便。

封装的特点:
 只能通过规定的方法访问数据。
隐藏类的实例细节,方便修改和实现。
实现封装的具体步骤如下:
 修改属性的可见性来限制对属性的访问,一般设为 private。
为每个属性创建一对赋值(setter)方法和取值(getter)方法,一般设为 public,用于属性的读写。
在赋值和取值方法中,加入属性控制语句(对属性值的合法性进行判断)。

例如:创建一个类,实现餐馆点菜的场景

public class  Restaurant1 {
   public static viod main(String[] args) {
       String cookName="Tom Cruise"; //厨师的名字叫Tom Cruise
       System.out.println("**请厨师为我做一份香辣肉丝。***");
       System.out.println(cookName + "加葱花");
       System.out.println(cookName + "洗蔬菜");
       System.out.println(cookName + "开始烹饪" + "香辣肉丝");
       System.out.println( "请问厨师叫什么名字?***");
       System.out.println(cookName)
       System.out.println( "**请厨师给我切一点葱花。***");
       System.out.println(cookName + "切葱花");

所有的逻辑代码全是在main方法中实现的,代码完全暴露,我可以任意删改。如果能随意修改代码,就无法正常运作。为防止其他人修改厨师行为将厨师单独封装成一个类,将厨师的工作定义成厨师类的行为。顾客与厨师是完全没有交集的,厨师是对顾客隐藏起来的,被封装在餐馆的类当中。这种编程模式就是封装。  封装的思想:将对象的属性和行为封装起来的载体就是类,类通常对顾客隐藏其实现细节。

7.2类的继承

继承在面向对象开发思想中是一个非常重要的概念,它使整个程序框架结构具有一定的弹性,还可以提 高软件的可维护性和可扩展性。

1.extends关键字

继承是面向对象的三大特征之一。继承和现实生活中的“继承”的相似之处是保留一些父辈的特性,从而减少代码冗余,提高程序运行效率。

Java 中的继承就是在已经存在类的基础上进行扩展,从而产生新的类。已经存在的类称为父类、基类或超类,而新产生的类称为子类或派生类。在子类中,不仅包含父类的属性和方法,还可以增加新的属性和方法。

 让一个类继承另一个类,用extends关键字,语法如下:

child  extends  parents

这里child这个类作为子类继承parents这个类,并继承parents中的属性和方法。

注意:Java中的类只支持单继承,即一个子类只能继承自一个父类。

public class PeopleTest {
    public static void main(String[] args) {
        // 创建Student类对象
        People stuPeople = new Student("王丽丽", 23, "女", "410521198902145589", "00001", "计算机应用与技术");
        System.out.println("----------------学生信息---------------------");
        System.out.println(stuPeople);
        // 创建Teacher类对象
        People teaPeople = new Teacher("张文", 30, "男", "410521198203128847", 5, "计算机应用与技术");
        System.out.println("----------------教师信息----------------------");
        System.out.println(teaPeople);
    }
} 

使用继承的注意点:
子类一般比父类包含更多的属性和方法。
父类中的 private 成员在子类中是不可见的,因此在子类中不能直接使用它们。
父类和其子类间必须存在“是一个”即“is-a”的关系,否则不能用继承。但也并不是所有符合“is-a”关系的都应该用继承。例如,正方形是一个矩形,但不能让正方形类来继承矩形类,因为正方形不能从矩形扩展得到任何东西。正确的继承关系是正方形类继承图形类。
Java 只允许单一继承(即一个子类只能有一个直接父类),C++ 可以多重继承(即一个子类有多个直接父类)。

2.方法的重写

在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

1、重写的实现

(1)继承并不只是扩展父类的功能,还可以重写父类的方法。

(2)重写(覆盖):在子类中将父类的成员方法的名称保留,重新编写成员方法的实现内容,更改成员方法的储存权限,或是修改成员方法的返回值类型。

(3)特殊的重写方式:子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现内容,这种方式被称为重构。

   注意:当重写父类方法时,修改方法的修饰权限只能从小范围到大的范围改变。
 

public class Animal {
public String name; // 名字 public int age; // 年龄

public Animal(String name, int age) {
this.name = name; this.age = age;

public String getInfo() {
return "我叫"+name +",今年"+age +"岁了。";

public class Cat extends Animal {
 private String hobby;

 public Cat(String name, int age, String hobby) {
 super(name, age); this. hobby = hobby;

 public String getInfo() {
 return "喵!大家好!我叫"+this.name +",我今年"+this.age +"岁了,我爱吃"+ hobby +"。"}

 public static void main(String[] args) {
 Animal animal =new Cat("小白",2,"鱼"); System.out.println(animal.getInfo());
}
 

 如上述代码,在 Animal 类中定义了一个返回值类型为 String、名称为 getInfo() 的方法,而 Cat 类继承自该类,因此 Cat 类同样含有与 Animal 类中相同的 getInfo() 方法。但是我们在 Cat 类中又重新定义了一个 getInfo() 方法,即重写了父类中的 getInfo() 方法。 

3.所有类的父类--object类

Object 是 Java 类库中的一个特殊类,也是所有类的父类。也就是说,Java 允许把任何类型的对象赋给 Object 类型的变量。当一个类被定义后,如果没有指定继承的父类,那么默认父类就是 Object 类。因此,以下两个类表示的含义是一样的

 

 7.3 类的多态

多态意为一个名字可具有多种语义。利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。类的多态可以从两个方面体现:一是方法的重载,二是类的上下转型。

1. 方法的重载

方法的重载意义:在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。

 重载与重写是两个完全不同的概念,重载主要用于一个类内实现若干重载的方法。这些方法的名称相同而参数形势不同;而重写主要用于子类继承父类时,重新实现父类中的非私有方法。

  对于int f( ) { }和void( ) { }两个方法,如果这样调用int result = f();,系统可以识别是调用返回值类型为 int 的方法,但 Java 调用方法时可以忽略方法返回值,如果采用如下方法来调用f();,你能判断是调用哪个方法吗?如果你尚且不能判断,那么 Java 系统也会糊涂。在编程过程中有一条重要规则就是不要让系统糊涂,系统一糊涂,肯定就是你错了。因此,Java 里不能用方法返回值类型作为区分方法重载的依据。

2.向上转型\向下转型

二者放一起概述

将一个类型强制转换成另一个类型的过程被称为类型转换。本节所说的对象类型转换,是指存在继承关系的对象,不是任意类型的对象。当对不存在继承关系的对象进行强制类型转换时,会抛出 Java 强制类型转换(java.lang.ClassCastException)异常。

Java 语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换。
 

Java 中引用类型之间的类型转换(前提是两个类是父子关系)主要有两种,分别是向上转型(upcasting)和向下转型(downcasting)。

1)向上转型
父类引用指向子类对象为向上转型,语法格式如下:
fatherClass obj = new sonClass();
其中,fatherClass 是父类名称或接口名称,
obj 是创建的对象,sonClass 是子类名称。

2)向下转型
与向上转型相反,子类对象指向父类引用为向下转型,语法格式如下:
sonClass obj = (sonClass) fatherClass;
其中,fatherClass 是父类名称,obj 是创建的对象,sonClass 是子类名称。

向上转型就是把子类对象直接赋给父类引用,不用强制转换。使用向上转型可以调用父类类型中的所有成员,不能调用子类类型中特有成员,最终运行效果看子类的具体实现。

向下转型可以调用子类类型中所有的成员,不过需要注意的是如果父类引用对象指向的是子类对象,那么在向下转型的过程中是安全的,也就是编译是不会出错误。但是如果父类引用对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现我们开始提到的 Java 强制类型转换异常,一般使用 instanceof 运算符来避免出此类错误。

向上转型

class Quadrangle {                             //四边形类
     public static void draw( Quadrangle q) {  //四边形类中的方法
             //SomeSentence
    }
 }
public class Parallelogram extends Quadrangle {  //平行四边形类,继承了四边形类
     public class void main(String args[]) {     //实例化平行四边形类对象引用
           Parallelogram p = new  Parallelogram();//调用父类方法
            draw(p);
     }
}

向下转型 

 class Restaurant  {
	public static void draw( Restaurant q) {
		//SomeSentence
	}
 }
   public class parallelogram extends  Restaurant {
	   public static void main(String[] args[]) {       
			       draw(new parallelogram () );
			       //将平行四边形类对象看作是四边形对象,称为向上转型操作
			       Restaurant q = new  parallelogram();
			       parallelogram p=q; //将父类对象赋予子类对象
	
                 //修改:parallelogram q= (parallelogram) q;		      
 
	}
 
}

4. instanceof关键字

严格来说 instanceof 是 Java 中的一个双目运算符,由于它是由字母组成的,所以也是 Java 的保留关键字。在 Java 中可以使用 instanceof 关键字判断一个对象是否为一个类(或接口、抽象类、父类)的实例,

1)声明一个 class 类的对象,判断 obj 是否为 class 类的实例对象(很普遍的一种用法),如以下代码:
Integer integer = new Integer(1);
System.out.println(integer instanceof  Integer);    // true
 
2)声明一个 class 接口实现类的对象 obj,判断 obj 是否为 class 接口实现类的实例对象,如以下代码:
Java 集合中的 List 接口有个典型实现类 ArrayList。
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
 
所以我们可以用 instanceof 运算符判断 ArrayList 类的对象是否属于 List 接口的实例,如果是返回 true,否则返回 false。
ArrayList arrayList = new ArrayList();
System.out.println(arrayList instanceof List);    // true
 
或者反过来也是返回 true
List list = new ArrayList();
System.out.println(list instanceof ArrayList);    // true
 
3)obj 是 class 类的直接或间接子类
我们新建一个父类 Person.class,代码如下:
public class Person {
}
 
创建 Person 的子类 Man,代码如下:
public class Man extends Person {
}

 class Quadrangle  {
	public static void draw(Quadrangle q) {
		//SomeSentence
	}
 }
class Square extends Quadrangle {
         //SomeSentence
class Anything {
       //SomeSentence
   public class parallelogram extends Quadrangle  {
	   public static void main(String[] args[]) {
                   Quadrangle q = new  Quadrangle         //实例化父类对象
                   //判断父类对象是否为Parallelogram子类的一个实例
                   if (q instanceof Parallelogram) {
                    Parallelogram p = (Parallelogram)  q;  //进行向下转型操作  
			       //判断父类对象是否为Parallelogram子类的一个实例
			       if (q instanceof Square) {
                    Square s = (Sauare) q;             //进行向下转型操作
                    }
                    //由于q对象不为Aaything类的对象,所以这条语句是错误的
                    //System.out.println(q instanceof Anything);		        
 
	}
 
}

 注意:instanceof是Java语言的关键字,在Java中的关键字都为小写。 

7.4抽象类与接口

1. 抽象类与抽象方法

Java 语言提供了两种类,分别为具体类和抽象类。前面学习接触的类都是具体类。这一节介绍一下抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类称为抽象类。

[权限修饰符]  abstract  class 类名  {undefined

         类体

}

 [权限修饰符]  abstract  方法返回值类型  方法名(参数列表);

 注意:构造方法不能定义为抽象方法。

抽象方法的 3 个特征如下:

抽象方法没有方法体
抽象方法必须存在于抽象类中
子类重写父类时,必须重写父类所有的抽象方法
 注意:在使用 abstract 关键字修饰抽象方法时不能使用 private 修饰,因为抽象方法必须被子类重写,而如果使用了 private 声明,则子类是无法重写的。

 public abstract class Market {undefined
 
public String name;     //商场名称
 
public String goods;     //商场名称
 
public abstract void shop();     //抽象方法,用来输出信息
————————————————
版权声明:本文为CSDN博主「蕾蕾1」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_67214194/article/details/124034922 public abstract class Market {undefined
 
public String name;     //商场名称
 
public String goods;     //商场名称
 
public abstract void shop();     //抽象方法,用来输出信息

使用抽象类和抽象方法时需要遵守以下原则:

(1)在抽象类中,可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须被定义为抽象类。

(2)抽象类不能直接实例化,即使抽象类中没有声明抽象方法,也不能实例化。

(3)抽象类被继承后,子类需要实现其中所有的抽象方法。

(4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。

 注意:构造方法不能定义为抽象方法。

2. 接口的声明及实现

抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是 Java 中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成。

接口是抽象类的延申,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。

一个接口实现一个接口可以使用implements关键字,代码如下: 

public class Parallelogram extends Quadrangle  implements drawTest {undefined

...//

}

3. 多重继承 

 多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承。有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需要思考的不是怎么使用多重继承,而是您的设计是否存在问题.但有时候我们确实是需要实现多重继承,而且现实生活中也真正地存在这样的情况,比如遗传:我们即继承了父亲的行为和特征也继承了母亲的行为和特征。可幸的是Java是非常和善和理解我们的,它提供了两种方式让我们曲折来实现多重继承:接口和内部类。

class 类名 implements 接口1,接口2,...,接口n

 通过类实现多个接口模拟家庭成员的继承关系。

public interface IFather {    //定义一个接口

void smoking();     //抽烟的方法

void goFishing();   //钓鱼的方法

}
 

4. 区分抽象类与接口

抽象类与接口是java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力。他们两者之间对抽象概念的支持有很大的相似,甚至可以互换,但是也有区别。

  尽管抽象类和接口之间存在较大的相同点,甚至有时候还可以互换,但这样并不能弥补他们之间的差异之处。下面将从语法层次和设计层次两个方面对抽象类和接口进行阐述。

定义一个IMother接口,并在其中定义两个方法wacthTV和cooking,代码如下:

public interface IMother {    //定义一个接口

  void wacthTV();   //看电视的方法

void cooking();       //做饭的方法
 

 创建名称为Me类,继承IFather和IMother两个接口

public class Me implements IFather, IMother { //继承IFather接口和IMother接口
	public void wacthTV()  {                  //重写wacthTV()方法
		System.out.println("我喜欢看电视");
	}
	public void cooking() {                  //重写cooking()方法  
		System.out.println("我喜欢做饭");
	}
	public void smoking() {                   //重写smoking()方法
		System.out.println("我喜欢抽烟");
	}
	public void goFishing() {                  //重写goFishing()方法
		System.out.println("我喜欢钓鱼");
	}
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		IFather fater = new Me();              //通过子类创建IFather接口对象
		System.out.println("爸爸的爱好:");
		father.smoking();  //使用接口对象调用子类中实现的方法
		father.goFishing();
		Mother mater = new Me();            //通过子类创建IMother接口对象
		System.out.println("\n妈妈的爱好:");
        mather.cooking();     //使用接口对象调用子类中实现的方法
        mather.wacthTV();
	}
 
}

7.5 访问控制

1. 访问控制符

所有访问控制符时,需要遵循以下原则。

(1)大部分顶级类都使用public修饰。

(2)如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰。

(3)类中的绝大部分属性都应该使用private修饰,除非一些static或者类似全局变量的属性,才会考虑使用public修饰;

(4)当定义的方法只是用于辅助实现该类的其他方法,应该使用private修饰;

(5)希望允许其他类自由调用的方法应该使用public修饰。
 在 Java 语言中提供了多个作用域修饰符,其中常用的有 public、private、protected、final、abstract、static、transient 和 volatile,这些修饰符有类修饰符、变量修饰符和方法修饰符。

2 .java类包

在编写 Java 程序时,随着程序架构越来越大,类的个数也越来越多,这时就会发现管理程序中维护类名称也是一件很麻烦的事,尤其是一些同名问题的发生。有时,开发人员还可能需要将处理同一方面的问题的类放在同一个目录下,以便于管理。

包允许将类组合成较小的单元(类似文件夹),它基本上隐藏了类,并避免了名称上的冲突。包允许在更广泛的范围内保护类、数据和方法。你可以在包内定义类,而在包外的代码不能访问该类。这使你的类相互之间有隐私,但不被其他世界所知。

包的 3 个作用如下:

区分相同名称的类。
能够较好地管理大量的类。
控制访问范围。
Java 中使用 package 语句定义包,package 语句应该放在源文件的第一行,在每个源文件中只能有一个包定义语句,并且 package 语句适用于所有类型(类、接口、枚举和注释)的文件。定义包语法格式如下:

package 包名;

Java 包的命名规则如下:

包名全部由小写字母(多个单词也全部小写)。
如果包名包含多个层次,每个层次用“.”分割。
包名一般由倒置的域名开头,比如 com.baidu,不要有 www。
自定义包不能 java 开头。

注意:如果在源文件中没有定义包,那么类、接口、枚举和注释类型文件将会被放进一个无名的包中,也称为默认包。在实际企业开发中,通常不会把类定义在默认包下。

3 final 关键字 

1.final类

 定义为final的类不能被继承

final的语法如下:

final class 类名{ }

 

 2.final 方法

 final方法不能被覆盖,定义一个为private的方法隐式被指定为final类型,这样无需将一个定义为private的方法再定义为final类型,例如下面:

 

 7.6  内部类

 1.成员内部类

1、成员内部类简介

 在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。

在内部类中可以随意使用外部类的成员方法以及成员变量。

成员内部类的语法如下:

public class OuterClass {      //外部类

   private class InnerClass  {   //内部类

           //...

    }

}
 

在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。
 
内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限。
 
内部类可以分为:实例内部类、静态内部类和成员内部类,每种内部类都有它特定的一些特点,本节先详细介绍一些和内部类相关的知识。
 
在类 A 中定义类 B,那么类 B 就是内部类,也称为嵌套类,相对而言,类 A 就是外部类。如果有多层嵌套,例如类 A 中有内部类 B,而类 B 中还有内部类 C,那么通常将最外层的类称为顶层类(或者顶级类)。

2.内部类的特点如下:

内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。

3、使用this关键字获取内部类与外部类的引用

 如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。

使用成员内部类时,应该遵循以下原则:

(1)可以有各种修饰符,可以用private、public、protectd、static、final 、abstract等修饰符。

(2)如果有内部类有static限定,就是类级别的,否则为对象级别.类级别可以通过外部类直接访问,对象级别需要先生成外部类的对象后才能访问;

(3)内部类不能同名;

(4)非静态内部类中不能声明任何static成员;

(5)内部类可以互相调用;

public class TheSameName {
   private int x;
  private class Inner {
    private int x = 9;
    public void doit (int_x) {
            x++;                        //调用的是形参x
            this.x++;                  //调用内部类的变量x
            TheSameName.this.x++;     //调用外部类的变量x
       }
   }
}

 2.匿名内部类

匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下:
 
new <类或接口>() {
    // 类的主体
};

匿名类有两种实现方式:

  • 继承一个类,重写其方法。
  • 实现一个接口(可以是多个),实现其方法
 
1)匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数。
public static void main(String[] args) {
    int a = 10;
    final int b = 10;
    Out anonyInter = new Out() {
        void show() {
            // System.out.println("调用了匿名类的 show() 方法"+a);    // 编译出错
            System.out.println("调用了匿名类的 show() 方法"+b);    // 编译通过
        }
    };
    anonyInter.show();
}
从 Java 8 开始添加了 Effectively final 功能,在 Java 8 及以后的版本中代码第 6 行不会出现编译错误,详情可点击《Java8新特性之Effectively final》进行学习。
 
2)匿名类中允许使用非静态代码块进行成员初始化操作。
Out anonyInter = new Out() {
    int i; {    // 非静态代码块
        i = 10;    //成员初始化
    }
    public void show() {
        System.out.println("调用了匿名类的 show() 方法"+i);
    }
};
3)匿名类的非静态代码块会在父类的构造方法之后被执行。

7.7 总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值