掘金 后端 ( ) • 2022-09-14 18:58

本文已参与「新人创作礼」活动,一起开启掘金创作之路。​

0️⃣写在前面

在上一篇文章《类与对象核心详解》中,我们介绍了Java类的基本概念和类的简单使用方法,本篇文章,我们继续来介绍Java类的特性。


1️⃣类的私用成员与公有成员

私有成员

使用场景: 限制外部对类中成员的访问,提高安全性。

如果没有一个机制来限制对类中成员的访问,很可能会造成错误的输入。

在Java语言中,在类的成员声明的前面加上修饰符private,则无法从该类的外部访问到该类内部的成员,而只能被该类的自身访问和修改,而不能被任何其他类(包括其子类)来获取或引用。因此达到了对数据最高级别保护的目的。

举例:在圆柱体Cylinder中,创建类的私有成员,使之在该类的外部无法访问该成员。

package practice;
class Cylinder{
private double radius;
private int height;
private double pi = 3.14;
double area() {
return piradiusradius;
}
double volume() {
return area() * height;
}
}
public class aaa {
public static void main(String[] args) {
// TODO Auto-generated method stub
Cylinder volu;
volu = new Cylinder();
volu.radius = 2.8;
volu.height =-5;
System.out.println("底圆半径="+volu.radius);
System.out.println("圆柱的高="+volu.height);
System.out.print("圆柱");
System.out.println("底面积="+volu.area());
System.out.println("圆柱体体积="+volu.volume());

}

该程序编译时将给出出错信息,说明无法在类Cylinder外部的任何位置访问该类内的私有成员。

公有成员

既然在外部无法访问类中的私有成员,那么Java提供了公共成员使得私有成员可以被外界访问。在Java语言中,在类的成员声明的前面加上修饰符public,则表示该成员可以被所有其他的类访问。例如,使用公共方法来访问私有成员。

举例:创建圆柱体类Cylinder的公共方法,来访问类内的私有成员变量。

package practice;
class Cylinder{
private double radius;
private int height;
private double pi = 3.14;
public void setCylinder(double r,int h) {
if(r>0 && h>0) {
radius = r;
height = h;
}else
System.out.println(“您的数据有错误!”);
}
double area() {
return piradiusradius;
}
double volume() {
return area() * height;
}
}

public class bbb {
public static void main(String[] args) {
// TODO Auto-generated method stub
Cylinder volu = new Cylinder();
volu.setCylinder(2.5, -5);
System.out.println("圆柱底面积="+volu.area());
System.out.println("圆柱体体积="+volu.volume());
}
}

程序运行结果为:

您的数据有错误! 圆柱底面积=0.0 圆柱体体积=0.0

该例中在Cylinder类内将setCylinder()方法声明为公共成员,并接收两个参数r和h。如果判断传进来的两个变量均大于0,则将私有数据成员radius设置为r,将height设置为h,否则输出“您的数据有错误!”的提示信息。

通过本例可以看出,唯有通过公共成员方法setCylinder(),私有成员radius和height才能得以修改。因此在公共成员方法内加上判断代码,可以杜绝错误数据的输入。本例第31行中刻意将volu的高设置为一5,所以私有成员radius和height并没有被赋值,其默认值为0,故输出的底面积值和体积值均为0。

缺省访问控制符

对于类成员(成员变量+成员方法)来说: 如果类成员的前面不加任何访问控制符,则该成员具有缺省的访问控制特性,表示这个成员只能被同一包(类库)中的类所访问和调用。

对于类来说: 如果一个类的前面不加任何访问控制符,则这个类具有缺省的访问控制特性,表示这个类只能被同一包(类库)中的类所访问和引用。


2️⃣方法的重载

方法的重载是实现“多态”的一种方法。 在面向对象的程序设计语言中,有一些方法的含义相同,但带有不同的参数,这些方法使用相同的名字,这就叫方法的重载(Overloading)。

也就是说,重载是指在同一个类内具有相同名称的多个方法,这些同名方法如果参数个数不同,或者参数个数相同,但类型不同,则这些同名的方法就具有不同的功能。

注意:方法的重载中参数的类型是关键,仅仅是参数的变量名不同是不行的。也就是说,参数的列表必须不同。即:或者参数个数不同,或者参数类型不同,或者参数的顺序不同。

举例:在圆柱体类cylinder中,利用方法的重载来设置成员变量

class cylinder
{
    private double radius;
    private int height;
    private double pi=3.14;
    private String color;
    public double setcylinder(double r,int h)
    {
        radius=r;
        height=h;
        return r+h;
    }
    public void setcylinder(String str)//重载方法
    {
        color=str;
    }
    public void show()
    {
        System.out.println("圆柱的颜色为:"+color);
    }
    double area() {//定义缺省访问控制符的方法
        return pi * radius * radius;
    }
    double volume()
    {
        return this.area() * height;
    }
}
public class sentence {
    public static void main(String[] args) {
        double r_h;
        cylinder volu=new cylinder();
        r_h=volu.setcylinder(2.5,5);
        volu.setcylinder("红色");
        System.out.println("圆柱低半径与高之和="+r_h);
        System.out.println("圆柱体体积="+volu.volume());
        volu.show();
    }
}

程序运行结果为:

圆柱底半径和高之和=7.5 圆柱体体积=98.5 圆柱的颜色为红色

由该例可知,通过方法的重载,只需一-个方法名称,却可拥有多个不同的功能,使用起来非常方便。由此可以看出,方法的重载是指同一类内定义多个名称相同的方法,然后根据其参数的不同(可能是参数的个数不同,或参数的类型不同)来设计不同的功能,以适应编程的需要。


3️⃣构造方法

前面所介绍的由Cylinder类所创建的对象,其成员变量都是在对象建立之后,再由相应的方法来赋值。如果一个对象在被创建时就完成了所有的初始化工作,将会很简洁。因此Java语言在类中提供了一个特殊的成员方法——构造方法。

构造方法的作用与定义

构造方法:在对象被创建时初始化对象成员的方法。

构造方法名称必须与它所在的类名完全相同。构造方法没有返回值,但在定义构造方法时,构造方法名前不能用修饰符void来修饰,这是因为一个类的构造方法的返回值类型就是该类本身。构造方法在对象创建时就会自动调用并执行。

举例:利用构造方法来初始化圆柱体类cylinder的成员变量

class cylinder
{
    private double radius;
    private int height;
    private double pi=3.14;
    public cylinder(double r,int h)//定义有参数的构造方法
    {
        radius=r;
        height=h;
    }
    double area() {//定义缺省访问控制符的方法
        return pi * radius * radius;
    }
    double volume()
    {
        return this.area() * height;
    }
}
public class sentence {
    public static void main(String[] args) {
        double r_h;
        cylinder volu=new cylinder(3.5,8);//调用有参构造方法创建对象
        System.out.println("圆柱低面积="+volu.area());
        System.out.println("圆柱体体积="+volu.volume());
    }
}

程序运行结果为:

圆柱底面积=38.465 圆柱体体积=307.72

由此可以看出,构造方法是一种特殊的、与类名相同的方法,专门用于在创建对象时,完成初始化工作。构造方法的特殊性主要体现在如下几个方面:

  1. 构造方法的方法名与类名相同。
  2. 构造方法没有返回值,但不能写void。
  3. 构造方法的主要作用是完成对类对象的初始化工作。
  4. 构造方法一般不能由编程人员显式地直接调用,而是用new来调用。
  5. 在创建一个类的对象的同时,系统会自动调用该类的构造方法为新对象初始化。

我们知道,在声明成员变量时可以为它赋初值,那么为什么还需要构造方法呢?这是因为,构造方法可以带上参数,而且构造方法还可以完成赋值之外的其他一些复杂操作,这在以后的内容中会进行讲解。

构造方法的重载

一般情况下,类都有一个或多个构造方法。但由于构造方法与类同名,所以当一个类有多个构造方法时,则这多个构造方法可以重载。我们已经知道,只要方法与方法之间的参数个数不同,或是参数的类型不同,便可定义多个名称相同的方法,这就是方法的重载。因此我们不难定义出构造方法的重载。构造方法的重载,可以让用户用不同的参数来构造对象。下面举例说明。

举例:在圆柱体类cylinder内使用构造方法的重载

package practice;
class Cylinder1{
private double radius;
private int height;
private double pi = 3.14;
String color;
public Cylinder1() {
radius = 1;
height = 2;
color = “绿色”;
}
public Cylinder1(double r,int h,String str) {
radius = r;
height = h;
color = str;
}
public void setColor() {
System.out.println(“该圆柱的颜色为=”+color);
}
double area(){
return piradiusradius;
}
double volume() {
return area()*height;
}
}
public class bbb {
public static void main(String[] args) {
// TODO Auto-generated method stub
Cylinder1 volu1=new Cylinder1();
System.out.println("圆柱1底面积="+volu1.area());
System.out.println("圆柱1体积="+volu1.volume());
volu1.setColor();
Cylinder1 volu2= new  Cylinder1(2.5,8,"红色");
System.out.println("圆柱2底面积="+volu2.area());
System.out.println("圆柱2体积="+volu2.volume());
volu2.setColor();
}

程序运行结果为:

圆柱1底面积=3.14 圆柱1体积=6.28 该圆柱的颜色为:绿色 圆柱2底面积=19.625 圆柱2体积=157.0 该圆柱的颜色为:红色

从一个构造方法调用另一个构造方法

为了某些特定的运算,Java语言允许在类内从某一构造方法内调用另一个构造方法。利用这个方法,可缩短程序代码,减少开发程序时间。从某一构造方法内调用另一构造方法,是通过关键字this来调用的。下面举例说明。

举例:在圆柱体类cylinde中,用一个构造方法调用另一个构造方法

package practice;
class Cylinder2{
private double radius;
private double pi=3.14;
private int height;
String color;
public Cylinder2() {
this(2.5,5,“红色”);
System.out.println(“无参构造方法被调用了”);
}
public Cylinder2 (double r,int h,String str) {
System.out.println(“有参构造方法被调用了”);
radius = r;
height = h;
color = str;
}
public void show() {
System.out.println(“圆柱底面半径为 =”+radius);
System.out.println(“圆柱体的高为=”+height);
System.out.println(“圆柱的颜色为=”+color);
}
double area() {
return piradiusradius;
}
double volume() {
return area()*height;
}
}
public class ccc {
public static void main(String[] args) {
// TODO Auto-generated method stub
Cylinder2 volu=new Cylinder2();
System.out.println("圆柱体底面积="+volu.area());
System.out.println("圆柱体体积="+volu.volume());
volu.show();
}

该程序运行结果为:

有参构造方法被调用了 无参构造方法被调用了 圆柱底面积=19.625 圆柱体体积=98.125 圆柱底半径为:2.5 圆柱体的高为:5 圆柱的颜色为:红色

注意:

  1. 在某一构造方法中调用另一构造方法时,必须使用this关键字来调用,否则编译时将出现错误。
  2. this 关键字必须写在构造方法内的第一行位置。

公共构造方法与私有构造方法

构造方法一般都是公有(public)的,这是因为它们在创建对象时,是在类的外部被系统自动调用的。如果构造方法被声明为private,则无法在该构造方法所在的类以外的地方被调用,但在该类的内部还是可以被调用的。

举例:创建圆柱体 类Cylinder,并在该类的一个构造方法内调用另一个私有的构 造方法。

package practice;
class Cylinder3{
private double radius;
private int height;
private double pi=3.14;
String color;
private Cylinder3() {
System.out.println(“无参构造方法被调用了”);
}
public Cylinder3(double r,int h,String str) {
this();
radius = r;
height = h;
color = str;
}
public void show() {
System.out.println("圆柱底半径为"+radius);
System.out.println("圆柱体的高为"+height);
System.out.println("圆柱体的颜色为"+color);
}
double area() {
return piradiusradius;
}
double volume() {
return area()*height;
}
}
public class ddd {
public static void main(String[] args) {
// TODO Auto-generated method stub
Cylinder3 volu = new Cylinder3(2.5,5,"蓝色 ");
System.out.println("圆柱体底面积="+volu.area());
System.out.println("圆柱体体积="+volu.volume());
volu.show();
}
}

程序运行结果为:

无参构造方法被调用了 圆柱底面积=19.625 圆柱体体积=98.125 圆柱底半径为:2.5 圆柱体的高为:5 圆柱的颜色为:蓝色


4️⃣类的静态成员

static称为静态修饰符,它可以修饰类中的成员。被static修饰的成员被称为静态成员,也称为类成员,而不用static修饰的成员称为实例成员。

实例成员

  • 不用static修饰的成员称为实例成员,它们属于对象(每个对象一份),通过对象访问,不能通过类。
  • 实例属性的初始化通常在定义时进行或在构造函数中进行。
  • 类内部,实例成员可以在实例方法中直接访问(成员前用this指代当前对象,可以省略,但当局部变量和成员变量重名时,this不能省略),不能在静态方法中直接访问,(静态方法中是不允许出现this的),这就解释了为什么被main方法直接调用的方法前要加static。

静态变量

Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享。静态成员可以使用类名直接访问,也可以使用对象名进行访问。

  1. 访问方式:通过类名.静态成员变量名进行访问
  2. 内存的存储方式:方法区
  3. 特点:静态的只有一份,且不依赖对象

静态方法

类似于静态变量,静态方法也属于类,不属于实例的。静态方法只能访问类的静态变量,或调用类的静态方法。通常静态方法作为工具方法,被其它类使用,而不需要创建类的实例。譬如集合类、Wrapper类(String, Integer等)和工具类(java.util中的类)都有很多静态方法。通常java程序的开始就是一个main()方法,它就是个静态方法。

例如:

package Hello;
 
public class Test {
 
void fun(){
System.out.println("这是一个普通方法");
}

static void fun1(){
System.out.println("这是一个静态方法");
}

public static void main(String[] args) {
Test test=new Test();
//调用普通方法
test.fun();
//调用静态方法
Test.fun1();
//调用静态方法
test.fun1();
}
}

程序运行结果为:

这是一个普通方法 这是一个静态方法 这是一个静态方法

静态初始化器

静态初始化器是由关键字static 修饰的一 对大括号“{}”括起来的语句组。它的作用与类的构造方法有些相似,都是用来初始化工作的,但静态初始化器与构造方法有几点根本的不同:

  1. 构造方法是对每个新创建的对象初始化,而静态初始化器是对类自身进行初始化。
  2. 构造方法是在用new运算符创建新对象时由系统自动执行,而静态初始化器一般不能由程序来调用,它是在所属的类被加载人内存时由系统调用执行的。
  3. 用new运算符创建多少个新对象,构造方法就被调用多少次,但静态初始化器则在类被加载人内存时只执行一次,与创建多少个对象无关。
  4. 不同于构造方法,静态初始化器不是方法,因而没有方法名、返回值和参数。

总之,静态初始化器的作用是对整个类完成初始化操作,包括给static成员变量赋初值,它在系统向内存加载时自动完成。


在这里插入图片描述