Java_面向对象编程-2

目录

主要内容

学习目标

第一节 static关键字

1.1. static变量

1.2. static方法

1.3. static代码块

第二节 package和import

2.1. package包

2.2. import导入

2.3. 使用文档注释生成API文档

第三节 封装性

3.1. 引入封装

3.2. 权限修饰符

3.3. 封装练习

第四节 继承性

4.1. 继承及其作用

4.2. 方法重写


主要内容

  1. static变量
  2. static方法
  3. static代码块
  4. package和import
  5. 封装性
  6. 继承性
  7. 方法重写

学习目标

节数

知识点

要求

第一节(static关键字)

static变量

理解

static方法

理解

static代码块

理解

第二节(package和import)

package

理解

import导入

掌握

使用文档注释生成API

了解

第三节(封装性)

封装的引入和作用

掌握

权限修饰符

掌握

第四节(继承性)

继承的引入和作用

掌握

方法重写

掌握

第一节 static关键字

        static是Java中的一个关键字,单词本身是静态的含义。一个类的成员包括变量、方法、构造方法、代码块和内部类,static可以修饰除了构造方法以外的所有成员。

        使用static修饰的成员成为静态成员,是属于某个类的;而不使用static修饰的成员成为实例成员,是属于类的每个对象的。

1.1. static变量

        在类中,用static声明的成员变量为静态成员变量,也称为类变量。 类变量的生命周期和类相同,在整个应用程序执行期间都有效。它有如下特点:

  1. 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
  2. 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
  3. 一般用“类名.类属性/方法”来调用。(也可以通过对象引用或类名(不需要实例化)访问静态成员。)
  4. 在static方法中不可直接访问非static的成员。

【示例1】static变量

public class Student {
    //成员变量
    private int sno;//学号
    private String name;//姓名
    private String sex;//性别
    private double score;//分数
    private String cup;//杯子
    //private static String waterDispenser;//饮水机
    private static String classRoom;//教室的编号
    //private static String teachName;//讲师的名字
//构造方法
    public Student(){
    }
    public Student(int sno, String name, String sex ){
        this.sno = sno;
        this.name = name;
        this.sex = sex;
    }
    public void show(){
        System.out.println(sno +"   "+this.name+"  "+sex+"  "
+this.score+"  "+classRoom);
    }
    public static void main(String[] args) {
        System.out.println(Student.classRoom);
        Student.classRoom = "503";
        System.out.println(Student.classRoom);

        Student stu = new Student(7,"田七","男",77);
        stu.sno = 5;
        //Student.sno = 6;
        stu.classRoom = "507";
        stu.show();
        Student stu2 = new Student();
        stu2.show();
    }
}

内存分配图如下:

总结:static变量和非static变量的区别:

  1. 份数不同:静态变量:1份;非静态变量:1个对象一份
  2. 存储位置不同:静态变量:方法区;非静态变量:堆中
  3. 内存分配空间的时间不同:静态变量:第一次加载类的时候;非静态变量:创建对象的时候
  4. 生命周期不同。静态变量和类的生命周期相同;非静态变量的生命周期和所属对象相同
  5. 调用方式不同
  • 静态变量:  通过类名调用  Student.classRoom,也可以通过对象名调用stu1.classRoom ="301" 不推荐
  • 非静态变量:通过对象名调用     stu1.name ="小张";

1.2. static方法

  • static方法的作用

                访问static变量和static方法

  • static方法的调用方式

                通过类名调用  Student.showClassRoom(); 推荐该方式

                通过对象名访问  stu1.showClassRoom();

  • 不可以

                静态方法中不可以访问非静态变量

                静态方法中不可以访问非静态方法

                静态方法中不可以访问this

                理解:加载类的时候就加载静态变量和静态方法,此时可能还没有创建对象,所以非静态变量和非静态的方法还没有分配空间,无法访问

  • 可以

                非静态方法中可以访问静态变量

                非静态方法中可以访问静态方法

               理解:加载类的时候就已经加载静态变量和静态方法,创建对象后,非静态变量和非静态的方法才分配空间,此时静态变量和静态方法已经存在,可以访问

【示例2】static方法

public class Student {
   //成员变量
   String name;
   int age;
   String sex;
   double score;
   static String classRoom;//103   !!!   
   public static void showClassRoom(){
      System.out.println(classRoom);
      //System.out.println(name);//非静态变量
      //shout();//非静态方法
      //System.out.println(this);
   }   
   public static void setClassRoom(String classRoom){
      Student.classRoom = classRoom;
   }
   //成员方法
   public void introduce(){
      System.out.println(this.name+"  "+this.age+"  "
+sex+"   "+score+"  "+classRoom);
      showClassRoom();
   }      
   public static void main(String[] args) {
      Student.showClassRoom();
      Student.setClassRoom("r301");
      Student.showClassRoom();      
      //Student stu1 = new Student("小王",20,"男",98);
      Student stu1 = new Student("小王",20,"男");
      stu1.name ="小张";
      stu1.classRoom ="r301";
      stu1.showClassRoom();
      }   
}

1.3. static代码块

  • 总结1:局部代码块
  1. 位置:方法中
  2. 数量:多个
  3. 执行顺序:依次执行
  4. 局部代码块中定义的变量作用范围只限于当前代码块
  •  总结2:(成员)代码块
  1. 位置:类中
  2. 数量:多个
  3. 执行顺序:依次执行
  4. 执行时间:每次创建对象的时候都执行;先执行代码块,再执行构造方法
  5. 作用:实际开发中很少用; 可以将各个构造方法中公共的代码提取到代码块;匿名内部类不能提供构造方法,此时初始化操作放到代码块中
  •  总结3:static代码块 
  1. 位置:类中
  2. 数量:多个
  3. 执行顺序:依次执行
  4. 执行时间:第一次加载类的时候执行,只执行一次
  5. 作用:给静态变量赋初始值。实际开发中使用比较多,一般用于执行一些全局性的初始化操作,比如创建工厂、加载数据库初始信息

【示例3】static代码块

public class Student {
   static {      
      System.out.println("static  code block 1");
   }
   String name;
   static String classRoom;//103   !!!
   static {
      //name = "sdf";
      classRoom = "r301";
      System.out.println("static  code block 2");
   }  
   public Student(){
      System.out.println("-----Student()---------");
   }
   public static void main(String[] args) {
      int n = 4;//局部变量
//    { //局部代码块
//       int m = 5;
//       System.out.println(m);
//    }
      System.out.println(classRoom);
      new Student();
      new Student();
  }
   {
      //classRoom = "r301";
      System.out.println(" code block 3");
   }
}

本节作业

  1. static变量和非static变量的区别和联系
  2. static方法为什么不可以访问非static的变量和方法
  3. static代码块的执行时机和执行次数


第二节 package和import

2.1. package

  • 为什么使用包

        文件太多,并且会有同名文件,计算机的硬盘需要不同级别的文件夹来存储;

        包机制是Java中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。除了以上考虑外,还和访问权限有密切关系

  • 如何定义包

        我们通过package实现对类的管理,package的使用有两个要点:

  1. 包名:域名倒着写即可,再加上模块名,便于内部管理类。
  2. 包名一律小写。

com.bjsxt.oop.object

cn.com.sina.video....

com.bjsxt.stumgr.dao

com.bjsxt.stumgr.dao.impl

  • 如何使用包

        通常是类的第一句非注释性语句。

        必须以;结尾。

  • Java常用包

Java中的常用包

说明

java.lang

包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。

java.awt

包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。

java.net

包含执行与网络相关的操作的类。

java.io

包含能提供多种输入/输出功能的类。

java.util

包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。

注意事项

  • 写项目时都要加包,不要使用默认包。
  • com.gao和com.gao.car,这两个包没有包含关系,是两个完全独立的包。只是逻辑上看起来后者是前者的一部分。 

2.2. import导入

        如果我们要使用其他包的类,需要使用import导入,从而可以在本类中直接通过类名来调用,否则就需要书写类的完整包名和类名。import后,便于编写代码,提高可维护性。

注意要点

  1. 默认是当前包的类和接口
  2. Java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用。
  3. 可以使用通配符,比如import com.bjsxt.oop.object.*; 会导入该包下所有类和接口(但不包括下级包)
  4. 如果导入两个同名的类,只能用包名+类名来显示调用相关类:

                java.util.Date date  = new  java.util.Date();

        静态导入(static  import)是在JDK1.5新增加的功能,其作用是用于导入指定类的静态属性和静态方法,这样我们可以直接使用静态属性和静态方法。 

【示例4】导入和静态导入

import java.lang.reflect.Constructor;
import java.util.Date;
import java.util.*;
import static java.lang.Math.PI;
import static java.lang.Math.*;
public class TestImport {
   public static void main(String[] args) {      
      Date date = new Date();
      java.sql.Date date2
            = java.sql.Date.valueOf("19990-12-23");      
      List list;
      Set set;
      Map map;
      Constructor constructor;
      System.out.println(PI);
      System.out.println(sqrt(64));
      System.out.println(pow(7, 2));    
   }
}

2.3. 使用文档注释生成API文档

        IntelliJ IDEA 本身提供了很好的 JavaDoc 生成功能,以及标准 JavaDoc 注释转换功能,其实质是在代码编写过程中,按照标准 JavaDoc 的注释要求,为需要暴露给使用者的类、方法以及其他成员编写注释。然后使用 IDEA 的功能自动调用 javadoc.exe(JDK 自带的工具)根据源代码中的注释内容自动生成 JavaDoc 文档(超文本格式)。

【示例5】使用文档注释

/**
 * 学生类
 */
public class Student {
    /**
     * 姓名
     */
    String name;
    /**
     * 年龄
     */
    int age;
    /**
     * 性别
     */
    String sex;

    /**
     * 学习
     */
    public void study(){
    }
    /**
     * 考试
     * @param site 地点
     * @return 分数
     */
    public double test(String site){
        return 100;
    }
}

 在idea中主要操作步骤如下:

 

最终可以生成如图所示的API帮助文档。

本节作业

  1. 理解package包的作用
  2. Java中常用包及其作用
  3. import导入的注意事项

第三节 封装性

       封装(encapsulation)是面向对象三大特征之一。对于程序合理的封装让外部调用更加方便,更加利于写作。同时,对于实现者来说也更加容易修正和改版代码。

3.1. 引入封装

        我要看电视,只需要按一下开关和换台就可以了。有必要了解电视机内部的结构吗?有必要碰碰显像管吗?制造厂家为了方便我们使用电视,把复杂的内部细节全部封装起来,只给我们暴露简单的接口,比如:电源开关。具体内部是怎么实现的,我们不需要操心。同理,汽车暴露离合、油门、制动和方向盘,驾驶员不需要懂原理和维修也可以驾驶。

        需要让用户知道的才暴露出来,不需要让用户知道的全部隐藏起来,这就是封装。说的专业一点,封装就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。

        我们程序设计要追求“高内聚,低耦合”。 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。

编程中封装的具体优点:

  1. 提高代码的安全性。
  2. 提高代码的复用性。
  3. “高内聚”:封装细节,便于修改内部代码,提高可维护性。
  4. “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。

【示例6】未进行封装的代码演示

class Person {
	String name;
	int age;
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
public class Test {
	public static void main(String[ ] args) {
		Person p = new Person();
		p.name = "小红";
		p.age = -45;//年龄可以通过这种方式随意赋值,没有任何限制
		System.out.println(p);
	}
}

        我们都知道,年龄不可能是负数,也不可能超过130岁,但是如果没有使用封装的话,便可以给年龄赋值成任意的整数,这显然不符合我们的正常逻辑思维。 

3.2. 权限修饰符

        Java是使用“访问控制符”来控制哪些细节需要封装,哪些细节需要暴露的。 Java中4种“访问控制符”分别为private、默认、protected、public,它们说明了面向对象的封装性,所以我们要利用它们尽可能的让访问权限降到最低,从而提高安全性。

        下面详细讲述它们的访问权限问题。其访问权限范围如表所示。

 访问权限修饰符

修饰符

同一个类

同一个包中

子类

所有包的所有类

private

*

默认

*

*

protected

*

*

*

public

*

*

*

*

  1. private 表示私有,只有自己类能访问
  2. default表示没有修饰符修饰,只有同一个包的类能访问
  3. protected表示可以被同一个包的类以及其他包中的子类访问
  4. public表示可以被该项目的所有包中的所有类访问

类的成员的处理:

  • 一般使用private访问权限。
  • 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头!)。
  • 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。

类的处理:

  • 类只能使用public和默认来修饰
  • 默认:当前包
  • public:当前项目的所有包
  • public类要求类名和文件名相同,一个java文件中至多一个public类

【示例7】封装后的代码演示

class Person {
	private String name;
	private int age;
	public Person() {
	}
	public Person(String name, int age) {
		this.name = name;
		setAge(age);
	}	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setAge(int age) {
		//在赋值之前先判断年龄是否合法
		if (age > 130 || age < 0) {
			this.age = 18;//不合法赋默认值18
		} else {
			this.age = age;//合法才能赋值给属性age
		}
	}
	public int getAge() {
		return age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
public class Test2 {
	public static void main(String[ ] args) {
		Person p1 = new Person();
		//p1.name = "小红"; //编译错误
		//p1.age = -45;  //编译错误
		p1.setName("小红");
		p1.setAge(-45);
		System.out.println(p1);		
		Person p2 = new Person("小白", 300);
		System.out.println(p2);
	}
}

3.3. 封装练习

以面向对象的思想,编写自定义类描述图书信息。设定属性包括:书名,作者,出版社名,价格;方法包括:信息介绍
要求:
        1) 设置属性的私有访问权限,通过公有的get,set方法实现对属性的访问
        2) 限定价格必须大于10,如果无效进行提示
        3) 设计构造方法实现对属性赋值
        4) 信息介绍方法描述图书所有信息
        5) 编写测试类,测试图书类的对象及相关方法(测试数据信息自定)

【示例8】对Book进行封装

public class Book {
    private  String bookName;//书名
    private String author;//作者
    private String publisher;//出版社
    private double price;//
    public Book(){
        //super();
    }
    public Book(String bookName,String author,String publisher,double price){
        this.bookName = bookName;
        this.author = author;
        this.publisher = publisher;
        //this.price = price;
        this.setPrice(price);
    }
    public void setBookName(String bookName){
        this.bookName = bookName;
    }
    public String getBookName(){
        return this.bookName;
    }
    public void setAuthor(String author){
        this.author = author;
    }
    public String getAuthor(){
        return author;
    }
    public String getPublisher(){
        return publisher;
    }
    public void setPublisher(String publisher){
        this.publisher = publisher;
    }
    public void setPrice(double price){
        if(price < 15){
            this.price = 10;
            System.out.println("价格必须大于10元,默认10元");
        }else{
            this.price = price;
        }
    }
    public double getPrice(){
        return this.price;
    }
    public void show(){
        System.out.println("bookName="+bookName+",author="
                +author+",price="+price+",publisher="+publisher);
    }
    public static void main(String[] args) {
        //购买第一本书
        Book book1 = new Book();
        //book1.price = 3;
        book1.setBookName("鹿鼎记");
        book1.setAuthor("金庸");
        book1.setPrice(7);
        book1.setPublisher("清华大学出版社");
        book1.show();
        //购买第二本书
        Book book2 =
                new Book("倚天屠龙记","金庸","清华大学出版社",30);
        book2.show();
        System.out.println(book1.getBookName());
    }
}

本节作业

  1. private、默认、protected、public四个权限修饰符的作用?
  2. 使用面向对象的思想,编写自定义描述狗的信息。设定属性包括:品种,年龄,心情,名字;方法包括:叫,跑。要求:
  1. 设置属性的私有访问权限,通过公有的get,set方法实现对属性的访问
  2. 限定心情只能有“心情好”和“心情不好”两种情况,如果无效输入进行提示,默认设置“心情好”。
  3. 设置构造函数实现对属性赋值
  4. 叫和跑的方法,需要根据心情好坏,描述不同的行为方式。
  5. 编写测试类,测试狗类的对象及相关方法(测试数据信息自定义)

运行效果图:

第四节 继承性

        继承(Inheritance)是面向对象编程的三大特征之一,它让我们更加容易实现对于已有类的扩展、更加容易实现对于现实世界的建模。

4.1. 继承及其作用

        继承让我们更加容易实现类的扩展。 比如,我们定义了人类,再定义Boy类就只需要扩展人类即可。实现了代码的重用,不用再重新发明轮子(don’t  reinvent  wheels)。

        从英文字面意思理解,extends的意思是“扩展”。子类是父类的扩展。现实世界中的继承无处不在。比如:

图5-1 现实世界中的继承 

         上图中,哺乳动物继承了动物。意味着,动物的特性,哺乳动物都有;在我们编程中,如果新定义一个Student类,发现已经有Person类包含了我们需要的属性和方法,那么Student类只需要继承Person类即可拥有Person类的属性和方法。

 【示例9】实现继承

public class Animal  {//extends Object
    private String color;//颜色
    private int age;//年龄
    public Animal() {
        super();
    }
    public Animal(String color, int age) { //alt+insert
        this.color = color;
        this.age = age;
    }
    public void eat(){
        System.out.println("eating ..........");
    }
    public void sleep(){
        System.out.println("sleeping............");
    }
    public void introduce(){
        System.out.println(color+"  "+age);
    }
}

public class Dog extends Animal{
    private String nickName;//昵称
    public Dog() {
    }
    public Dog(String color,int age){
    }
    public Dog(String color,int age,String nickName){
//        this.color = color;
//        this.age = age;
        super(color,age);
        this.nickName = nickName;
    }
    public void guard(){
        System.out.println("Dog guarding......");
    }
}
public class Cat extends  Animal {
    private int eysSight;//视力
    public Cat() {
        super();//默认调用父类的无参数构造方法
    }
    public Cat(String color, int age, int eysSight) {
        super(color,age);
        this.eysSight = eysSight;
    }
    public  void grabMouse(){
        System.out.println("Cat grab mouse..........");
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("黑色",3,"旺财");
        dog.eat();//从父类继承的方法
        dog.sleep();//从父类继承的方法
        dog.introduce();//从父类继承的方法
        dog.guard();//子类特有的方法
        
        Cat cat = new Cat("花色",3,5);//alt+enter
        cat.eat();
        cat.sleep();
        cat.introduce();
        cat.grabMouse();
    }
}

继承使用要点

  1. 父类也称作超类、基类。子类:派生类等。
  2. Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
  3. 子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。
  4. 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。

4.2. 方法重写

        父类的方法introduce()已经无法满足子类的需求,怎么办?同理,Object类的toString()已经无法满足Animal类、Dog类的需求,怎么办?可通过方法重写(override)解决,或者称为方法覆盖。

【示例10】实现方法重写

public class Animal {//extends Object
    protected String color;//颜色
    private int age;//年龄
    public Animal() {
        super();
    }
    public Animal(String color, int age) { 
        this.color = color;
        this.age = age;
    }
   public void introduce(){
        System.out.println(color+"  "+age);
    }
    @Override
    public String toString() {
        //return super.toString();
        return "Animal[color="+color+",age="+age+"]";
    }
}
public class Dog extends Animal{
    private String nickName;//昵称
    public Dog() {
    }
    public Dog(String color, int age){
    }
public Dog(String color, int age, String nickName){
//        this.color = color;
//        this.age = age;
        super(color,age);
        this.nickName = nickName;
    }
    public  void introduce(){
        //this.introduce();
        //super.introduce();
        System.out.println(color+"  "+this.getAge()+"  "+nickName);
    }
    public void guard(){
        //this.guard();
        //super.guard();
        System.out.println("Dog guarding......");
    }
    @Override
    public String toString() {
        //return super.toString()+" "+nickName;
        return "Dog[name="+color+",age="+getAge()+
",nickName="+this.nickName+"]";
    }
}

方法重载和方法重写(覆盖)是面向对象中两个重要概念,其实这两个概念之间没有什么关系,但是毕竟都是关于方法的,毕竟容易引起混淆。对此我也做了一些归纳,感觉能够把这两个概念很好的区分开。我打算从总体区别、细节区别两个方面来说明。

总体的区别:最主要的区别,是解决的问题不同,即作用不同。

英文

位置不同

作用不同

重载

overload

同一个类中

在一个类里面为一种行为提供多种实现方式并提高可读性

重写

override

子类和父类间

父类方法无法满足子类的要求,子类通过方法重写满足要求

细节的区别:一个方法的声明自左向右包括权限修饰符、方法返回值、方法名、参数列表、抛出的异常类型等。下面从这几方面说明区别

修饰符

返回值

方法名

参数

抛出异常

重载

无关

无关

相同

不同

无关

重写

大于等于

小于等于

相同

相同

小于等于

重载实例:构造方法重载、println()方法重载

重写实例:Object类的toString()equals()hashCode()等都可以被子类重写

可选

  1. 某些方法使用final修饰,将无法被重写。比如Object类的wait()、notify()等
  2. 静态方法无法进行方法重写。在Java中,如果父类中含有一个静态方法,且在子类中也含有一个返回类型、方法名、参数列表均与之相同的静态方法,那么该子类实际上只是将父类中的该同名方法进行了隐藏,而非重写。添加@override注解将会报错。

本节作业

  1. 继承的作用
  2. 定义父类Animal、定义Dog、Cat类继承Animal类
  3. 方法重写和方法重载的比较
  4. 重写Animal、Dog、Cat的toString()

猜你喜欢

转载自blog.csdn.net/weixin_45859844/article/details/120461449