JavaSE-面向对象编程-第二篇

本文详细讲解了Java中的面向对象编程概念,包括static关键字的使用,如静态变量、方法和代码块,以及package和import的作用。此外,文章还深入探讨了封装性,介绍了权限修饰符的应用和封装的意义,提供了封装练习。最后,文章阐述了继承性,讨论了继承的作用和方法重写的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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变量的区别:

static非static
份数不同1份1个对象一份
存储位置不同方法区中堆中
内存分配空间的时间不同第一次类被加载的时候创建对象的时候
生命周期不同和类的生命周期相同和所属的对象生命周期相同
调用方式不同1.通过类名调用 Student.classRoom 2. 通过对象名调用 stu1.classRoom=“301”(不推荐使用)通过对象名调用 stu1.name=“小张”

1.2 static方法

  1. 作用:访问static变量和static方法
  2. 调用方式:
    通过类名调用 Student.showClassRoom(); 推荐该方式
    通过对象名访问 stu1.showClassRoom();
  3. 不可以访问的三种情况:
    静态方法中不可以访问非静态变量
    静态方法中不可以访问非静态方法
    静态方法中不可以访问this
    理解: 加载类的时候就加载静态变量和静态方法,此时可能还没有创建对象,所以非静态变量和非静态的方法还没有分配空间,因此无法访问。
  4. 两个可以:
    非静态方法中可以访问静态变量
    非静态方法中可以访问静态方法
    理解: 加载类的时候就已经加载静态变量和静态方法,创建对象后,非静态变量和非静态的方法才分配空间,此时静态变量和静态方法已经存在,因此可以访问。

【示例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代码块

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

【示例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");
   }
}

二、 package和import

2.1 package包

  1. 为什么使用包
    文件太多,并且会有同名文件,计算机的硬盘需要不同级别的文件夹来存储;
    包机制是Java中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。除了以上考虑外,还和访问权限有密切关系。
  2. 如何定义包
    我们通过package实现对类的管理,package的使用有两个要点:
    (1) 包名:域名倒着写即可,再加上模块名,便于内部管理类。
    (2) 包名一律小写。
    在这里插入图片描述
  3. 如何使用包
    (1)通常是类的第一句非注释性语句。
    (2)必须以;结尾。
  4. java常用包

    在这里插入图片描述

注意事项

1. 写项目时都要加包,不要使用默认包。
2. 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帮助文档。


在这里插入图片描述

三、封装性

封装(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,它们说明了面向对象的封装性,所以我们要利用它们尽可能的让访问权限降到最低,从而提高安全性。

权限范围:

在这里插入图片描述

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

类的成员的处理:

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

类的处理:

  1. 类只能使用public和默认来修饰
  2. 默认:当前包
  3. public:当前项目的所有包
  4. 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());
    }
}

四、继承性

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

4.1 继承及其作用

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

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

在这里插入图片描述
上图中,哺乳动物继承了动物。意味着,动物的特性,哺乳动物都有;在我们编程中,如果新定义一个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+"]";
    }
}

总结:


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值