JavaSE学习总结(五)面向对象(上)面向对象的思想/类与对象/成员变量和局部变量区别/匿名对象/private、this、static关键字/构造方法/静态变量和成员变量区别/Math类获取随机数

面向对象(上)

一、面向过程与面向对象

(一)面向过程思想概述

  面向过程就是分析出解决问题所需要的步骤,然后用方法把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
  而具体的每一步都需要我们去实现和操作。这些步骤相互调用和协作,完成我们的需求。在上面的每一个具体步骤中我们都是参与者,并且需要面对具体的每一个步骤和过程,这就是面向过程最直接的体现。
  那么什么是面向过程开发呢? 面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。

面向过程的代表语言:C语言

(二)面向对象思想概述

  当需求单一,或者简单时,我们一步一步去操作没问题。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了。这时就我们开始思索,能不能把这些步骤和功能再进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。
  面向对象就是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
  那么什么是面向对象开发呢?面向对象开发就是不断地创建对象,使用对象,指挥对象做事情,从而完成需求。

(三)面向对象思想特点

(1)是一种更符合我们思想习惯的思想
(2)可以将复杂的事情简单化
(3)将我们从执行者变成了指挥者,角色发生了转换

(四)面向对象思想在生活中的例子

  在生活中,面向过程的思想就好比手洗衣服,首先需要接盆水,然后把衣服放进去,再倒上洗衣液,然后用手揉搓衣服,再漂净衣服,最后晾干。这其中的每一步都需要我们一步步实现,每一步我们都是参与者。
  而面向对象,则是我们可以买一台全自动洗衣机,只需要按下按键即可完成洗衣服(调用类中方法)。

(五)面向对象的特征

1.封装
封装性是面向对象编程的核心思想

指的就是将描述某种实体的数据和基于这些数的操作集合到一起,形成一个封装体

封装的思想保证了类内部数据结构的完整性,使用户无法轻易直接操作类的内部数据,这样降低了对内部数据的影响,提高了程序的安全性和可维护性。

2.继承

继承是Java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或类从父类继承方法,使得子类具有父类相同的行为。

3.多态
多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。

接口的多种不同的实现方式即为多态。

二、类与对象概述

  • 这个现实世界是由事物组成。生活中我们如何描述现实世界事物?
    举例: 描述学生
    属性:姓名 , 年龄 , 性别 …
    行为:学习 , 吃饭 , 睡觉 …

  • 属性: 就是该事物的描述信息
    行为: 就是该事物能够做什么

    编程语言,就是为了模拟现实中的事物,我们学习的Java语言最基本单位是类,所以,我们就应该把事物用一个类来体现。

  • 由此我们就得到了现实中的事物和类的对应关系
    事物 ----------------- 类
    属性 ----------------- 成员变量
    行为 ----------------- 成员方法

  • 定义类其实就是定义类的成员(成员变量和成员方法)
    (1)成员变量 和以前定义变量是一样的,只不过位置发生了改变。在类中,方法外。
    (2)成员方法 和以前定义方法是一样的,只不过把static去掉,后面在详细讲解static的作用。

  • 类和对象的概念
    (1)类:是一组相关的属性和行为的集合
    (2)对象:是该类事物的具体体现
    (3)举例:
    类——学生
    对象——班长

三、类与对象应用

1.学生类
定义一个学生类

public class Student {
    //属性——————成员变量
    //成员变量要定义在类中方法外
    String name;//可以给属性赋初值,不赋值的情况下为该数据类型的默认值,此处为null
    int age;//默认值0
    char sex;//默认值空字符
    //行为——————成员方法
    public void study(){
        System.out.println("正在学习中...");
    }
    public void eat(){
        System.out.println("正在吃饭中...");
    }
    public void sleep(){
        System.out.println("正在睡觉中...");
    }
}

同一个包下,定义一个测试类创建对象并调用类属性和功能

public class MyTest {
    public static void main(String[] args) {
        //定义一个类,体现的就是封装的思想---封装了成员变量和成员方法
        //定义一个类使用关键字 class
        //我要定义一个学生类
        //类是一个抽象的概念,你无法直接使用他的属性和功能,我们要使用该类,那必须要对类进行实例化
        //所谓实例化,就是创建该类的对象。如何创建一个类的对象呢?使用关键字new
        //创建该类的实例(对象)
        Student st = new Student();
        //设置属性的值
        st.name="张三";
        st.age=18;
        st.sex='男';
        //有了对象以后,通过对象调用类中的属性和功能
        //获取属性 对象名.属性名
        String name=st.name;
        int age=st.age;
        char sex=st.sex;
        System.out.println(name);
        System.out.println(age);
        System.out.println(sex);
        //调用方法 对象名.方法名()
        st.eat();
        st.sleep();
        st.study();
        System.out.println("------------------------------------");
        //一个类可以创建很多对象
        Student st2 = new Student();
        st2.name="小红";
        st2.age=19;
        st2.sex='女';
        System.out.println(st2.name);
        System.out.println(st2.age);
        System.out.println(st2.sex);
        st2.eat();
        st2.sleep();
        st2.study();
    }
}

在这里插入图片描述
2.老师类
定义一个老师类

public class Teacher {
    String name;
    int age;
    public void teach(){
        System.out.println("正在教课中...");
    }
    public void sleep(){
        System.out.println("正在休息中...");
    }
}

同一个包下,定义一个测试类创建对象并调用类属性和功能

public class MyTest {
    public static void main(String[] args) {
        Teacher t1 = new Teacher();
        t1.name = "张三";
        t1.age = 26;
        System.out.println(t1.name);
        System.out.println(t1.age);
        Teacher t2 = new Teacher();
        t2.name = "赵四";
        t2.age = 27;
        Teacher t3=t1;
        t3.name="田七";
        t1.age=30;
        System.out.println(t1.name);
        System.out.println(t1.age);
        System.out.println(t2.name);
        System.out.println(t2.age);
        System.out.println(t3.name);
        System.out.println(t3.age);
    }
}

在这里插入图片描述
内存解析
在这里插入图片描述
首先.class文件被加载进方法区,main方法被调用进栈,执行到第一句代码时,堆内存为t1对象开辟空间,并赋了默认值,再将空间的地址赋给t1这个引用,因此t1便指向了该空间。执行到第二、三句代码,便通过t1找到空间,将name改为“张三”,age改为26,此时的输出就为“张三”和26。再执行下面的代码,堆内存为t2对象开辟空间并初始化默认值,再将空间的地址赋给t2这个引用,接着再将name改为“赵四”,age改为27。然后,将t1这个引用赋给t3,t3并没有new,所以没有开辟新的空间,而是指向了t1指向的空间,因此t1和t3共同操作一个空间。最后将t3.name改为“田七”,也即改变了t1.name,又将t1.age改为30,于是后面的输出便为“田七”,30,“赵四”,27,“田七”,30。

四、成员变量和局部变量的区别

  • 在类中的位置不同
    成员变量:在类中方法外
    局部变量:在方法定义中或者方法声明上(形参)
  • 在内存中的位置不同
    成员变量:在堆内存
    局部变量:在栈内存
  • 生命周期不同
    成员变量:随着对象的创建而存在,随着对象的消失而消失
    局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
  • 初始化值不同
    成员变量:有默认初始化值
    局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。

注意事项:局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则

变量的访问原则——就近原则:方法中要访问一个变量,会先在局部位置找,找到就使用;如果找不到,会找成员变量,找到就使用 。

案例演示
1.

/*
一个Java文件中,可以定义多个类,
注意:public只能有一个,在有main方法的类前面加上,其他类不能加public
*/
public class MyTest {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.test("汤姆");
    }
}
/*
变量的访问原则——就近原则:方法中要访问一个变量,会先在局部位置找,找到就使用
如果找不到,会找成员变量,找到就使用     
 */
class Cat{
    //成员变量
    String name="发财";
    //方法内部的变量和形参都属于局部变量
    public void test(String name){
        System.out.println(name);
    }
}

此时test方法中需要输出name,先找局部变量,发现形参名字就为name,于是输出汤姆,而不会先去找成员变量。
在这里插入图片描述
而将代码改一下:

public class MyTest {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.test("汤姆");
    }
}
class Cat{
    //成员变量
    String name="发财";
    //方法内部的变量和形参都属于局部变量
    public void test(String name1){
        String name="杰克";
        System.out.println(name);
    }
}

此时test方法中需要输出name,先找局部变量,发现方法内部的变量name,于是输出杰克,而不会先去找成员变量。
在这里插入图片描述
2.

public class MyTest {
    public static void main(String[] args) {
        //基本数据类型,作为参数传递,形参的改变,不影响实参
        //引用输入类型,作为参数传递,形参的改变,会影响实参
        //引用数据类型:数组,类,接口
        Dog dog = new Dog();
        String name = "小白";
        int age = 3;
        //如果看到一个方法的形参,数据类型是类,那么就传一个该类的对象
        dog.show(dog, name, age);
        System.out.println(dog.name);
        System.out.println(dog.age);
        System.out.println(name);
        System.out.println(age);
    }
}

class Dog {
    String name;
    int age;

    public void show(Dog d, String name, int age) {
        name = "汪汪";
        age = 2;
        d.name = name;
        d.age = age;
        System.out.println(name);
        System.out.println(age);
    }
}

在这里插入图片描述
内存解析
在这里插入图片描述

五、匿名对象

(一)什么是匿名对象?

匿名对象:就是没有名字的对象,是对象的一种简化表示形式

(二)匿名对象应用场景

  • 调用方法,仅仅只调用一次的时候
  • 匿名对象可以作为实际参数传递

(三)匿名对象说明

  • 匿名对象也是一个对象,具有对象的所有功能
  • 每一次使用匿名对象时,都是一个新的对象,是不同的对象。

(四)匿名对象优点

  • 由于匿名对象只在堆内存中开辟空间,而不存在栈内存的引用,所以匿名对象调用完就被垃圾回收器回收,提高了内存使用效率。
  • 如果要执行的任务需要一个对象,但却不值得创建全新的对象(原因可能是所需的类过于简单,或者是由于它只在一个方法内部使用),匿名类就显得非常有用

(五)案例演示(匿名对象应用场景)

1.调用方法,仅仅只调用一次的时候。
public class MyTest {
    public static void main(String[] args) {
        //普通对象调用成员变量及方法
        Cat c = new Cat();
        c.age=3;
        int age = c.age;
        System.out.println(age);
        c.eat();
        //匿名对象调用成员变量及方法
        int age1=new Cat().age;//匿名对象调用成员变量,每new一次就产生一个新的对象
        System.out.println(age1);
        new Cat().eat();//匿名对象的方法调用,每new一次就产生一个新的对象
    }
}
class Cat{
    int age=2;
    public void eat(){
        System.out.println("吃鱼");
    }
}

在这里插入图片描述


  • 问:为什么匿名对象只适合对方法的一次调用?
    答:因为调用多次就会创建多个对象,每次调用都是不同的对象,那么就失去了实际意义,此时还不如用普通的有对象名的对象。
    如果需要一个对象进行方法调用2次,使用匿名对象的方式无法实现:
new Cat().eat();
new Cat().eat();

这是2个Cat类的对象分别调用了eat()方法,而不是一个对象调用了两次方法。

  • 问:匿名对象是否可以调用属性并赋值?有什么意义?
    答:匿名对象可以调用属性并赋值,但是没有意义,无法再次使用,因为调用后就变成垃圾。如果需要赋值还是用有对象名的对象。语法上,匿名对象只创建对象,但是不用变量来接收。

2.匿名对象可以作为实际参数传递
public class MyTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        //如果看到一个方法的形参的数据类型为类,那么就传一个该类的对象
        cat.show(cat, 19);
        System.out.println(cat.num);
        System.out.println("---------------------");
        //匿名对象可以作为参数传递
        cat.show(new Cat(), 20);
        System.out.println(cat.num);
    }
}
class Cat {
    int num = 100;
    public void show(Cat cat, int num) {
        cat.num = num;
        System.out.println(cat.num);
    }
}

在这里插入图片描述

六、封装(private关键字)

先来看一个例子:

public class Person {
    String name;
    int age;

    public void show() {
        System.out.println(name);
        System.out.println(age);
    }
}
public class MyTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.name="张三";
        p.age=-10;
        p.show();
    }
}

在这里插入图片描述
本例通过 对象名.成员变量名=值 这种方式给成员变量设置值,但是不能排除一些不合理的数据,就比如年龄不可能为-10岁,我们希望能够对给成员变量设置的数据进行一些校验,那么我们就可以屏蔽掉 对象名.成员变量名=值 这种设置方式。
那么怎么屏蔽掉呢?可以使用关键字 private

(一)private关键字特点

  • 是一个权限修饰符
  • 可以修饰成员变量和成员方法
  • 被其修饰的成员只能在本类中被访问

对比:public是一个权限修饰符,可以修饰类,可以修饰成员变量和成员方法,被修饰的成员在任何地方都可以访问。

案例演示

public class Person {
    String name;
    //private 是一个权限修饰符,私有的,可以修饰成员变量、成员方法,被修饰的成员,只能在本类中访问,外界无法访问。
    private int age;//加上了private权限修饰符,私有成员变量

    public void show() {
        System.out.println(name);
        System.out.println(age);
    }
}

在这里插入图片描述
同理,如果成员方法前面的权限修饰符不是public而是private,那么该方法也无法在其他类中被调用。

成员变量被隐藏起来了无法被外界访问了,那么我们如何给创建的对象设置属性值呢?
这时我们就可以在定义的类中提供公共的访问方法,从而修改对象的属性。

public class Person {
    String name;
    private int age;//加上了private权限修饰符,私有成员变量

    public void show() {
        System.out.println(name);
        System.out.println(age);
    }
    public void setName(String n) {//通过公共的set方法设置其属性
        name = n;
    }
    public void setAge(int a) {//通过公共的set方法设置其属性
        if(a>=0&&a<=120){//对数据进行校验
            age = a;
        }
        else{
            System.out.println("输入年龄不合逻辑!");
        }
    }
}
public class MyTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.name="张三";//依旧可以访问到name这个成员变量。
        //p.age=-10;无法直接访问被private修饰的属性
        p.setAge(10);//但可以通过公共的set方法设置其属性
        p.show();
        System.out.println("--------------");
        Person p1 = new Person();
        p1.setName("赵四");
        p1.setAge(-10);
        p1.show();
    }
}

在这里插入图片描述
现在我们解决了设置私有属性的值的问题,那么假设我们需要获取对象的私有属性又该怎么办呢?
同样地,我们可以在类中提供公共的访问方式,返回该对象的属性值即可。

public class Person {
    String name;
    private int age;//加上了private权限修饰符,私有成员变量

    public void setName(String n) {
        name = n;
    }
    public void setAge(int a) {
        if(a>=0&&a<=120){
             age= a;
        }
        else{
            System.out.println("输入年龄不合逻辑!");
        }
    }
    public String getName() {//返回name
        return name;
    }
    public int getAge() {//返回age
        return age;
    }
}
public class MyTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.name="张三";//依旧可以访问到name这个成员变量。
        //p.age=-10;无法直接访问被private修饰的属性
        p.setAge(10);//但可以通过公共的set方法设置其属性
        String name=p.getName();//获取对象p的name
        int age=p.getAge();获取对象p的age
        System.out.println(name+" "+age);

        Person p1 = new Person();
        p1.setName("赵四");
        p1.setAge(20);
        String name1=p1.getName();
        int age1=p1.getAge();
        System.out.println(name1+" "+age1);
    }
}

在这里插入图片描述
上述的几个例子就体现了封装的思想。

(二)封装概述

是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

(三)封装好处

  • 隐藏实现细节,提供公共的访问方式
  • 提高了代码的复用性
  • 提高安全性。

(四)封装原则

将不需要对外提供的内容都隐藏起来。
把属性隐藏,提供公共方法对其访问。

七、this关键字

先来看一个例子:
假如set方法中,局部变量(形参)和成员变量同名了,那么当该set方法被调用时还会改变对象的属性值吗?

public class Person {
    String name;
    private int age;

    public void setName(String name) {
        name = name;
    }
    public void setAge(int age) {
        age= age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public void show(){
        System.out.println(name+" "+age);
    }
}
public class MyTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.setName("张三");
        p.setAge(10);
        p.show();
    }
}

在这里插入图片描述
从结果我们发现输出并不是张三和10,证明该对象的属性并没有被修改,仍然是默认值。这是因为“就近原则”,set方法中的两个name都是指的局部变量(形参)的那个name,也即局部变量name自己赋给自己,并没有改变成员变量name,因此我们需要一个关键字this来解决此问题:

public class Person {
    String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age= age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public void show(){
        System.out.println(name+" "+age);
    }
}
public class MyTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.setName("张三");//p调用了set方法,那么set方法中的this就代表p。
        p.setAge(10);
        p.show();
    }
}

在这里插入图片描述

(一)为什么要有this

当我们的局部变量和成员变量重名的时候,如果我们不使用this关键字,那么会导致一个问题:就是局部变量隐藏了成员变量的问题

(二)this关键字特点

是当前类的对象引用。
简单的记,它就代表当前类的一个对象。谁调用这个方法,那么该方法的内部的this就代表谁

public class MyTest {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a);//a的地址
        int num=10;
        a.show(num,a);
        System.out.println(num); //就近原则
    }
}
class A{
    int num=100;
    public void show(int num, A a){
        System.out.println(this);//与a的地址相同
        System.out.println(num);//就近原则 
        System.out.println(a.num); 
        System.out.println(this.num);
        System.out.println(a==this);//this实际上就相当于正调用该方法的对象
    }
}

在这里插入图片描述

八、构造方法

假设有一个类A,那么创建一个A类对象:A a=new A();,这个A()其实是一个方法,叫做构造方法。

(一)构造方法概述和格式

  • 构造方法概述和作用
    创建对象,给对象中的成员进行初始化
  • 构造方法格式特点
    (1)方法名与类名相同
    (2)没有返回值类型,连void都没有
    (3)没有具体的返回值

(二)构造方法的重载

1.案例演示

构造方法的重载

public class Student {
    String name;
    int age;
    //构造方法:方法名和类名相同,没有返回值类型,连void 也没有
    //我们自定义的一个类中,即使不写构造方法,默认也会存在一个空参的构造方法
    //构造方法,就是用来初始化这个类的,完成对类的实例化
    public Student(){
        System.out.println("无参构造方法执行了");
    }
    public Student(String name){//构造方法的重载
        this.name=name;
        System.out.println("一个参数的构造方法执行了");
    }
    public Student(String name,int age){//构造方法的重载
        this.name=name;
        this.age=age;
        System.out.println("两个参数的构造方法执行了");
    }
}
public class MyTest {
    public static void main(String[] args) {
        //类,是一个抽象的概念,不能直接使用,要使用类中的属性和功能,必须对类进行实例化(创建对象)
        //我们在创建对象时,除了使用关键字new之外,还得借助构造方法,来完成对类的实例化。
        //借助空参的构造方法创建对象
        Student st1 = new Student();
        System.out.println(st1.name);
        System.out.println(st1.age);
        //借助有参的构造方法创建对象
        Student st2 = new Student("张三");
        System.out.println(st2.name);
        System.out.println(st2.age);
        Student st3 = new Student("赵四", 20);
        System.out.println(st3.name);
        System.out.println(st3.age);
    }
}

在这里插入图片描述

2.构造方法注意事项
  • 如果我们没有给出构造方法,系统将自动提供一个无参构造方法。
  • 如果我们给出了构造方法,系统将不再提供默认的无参构造方法。
    注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出。建议永远自己给出无参构造方法。

如下:
在这里插入图片描述
此时即使Dog类中没有写构造方法,创建Dog类的对象时也不会报错,因为默认存在一个无参构造方法。
在这里插入图片描述
但是如果我们给出了有参构造方法,那么默认的无参构造方法就没有了,此时若用无参构造方法创建对象会报错。
在这里插入图片描述
如果你还想要使用无参构造来创建对象,建议你手动写出来,也建议你永远手动写出来。

3.给成员变量赋值的两种方式
  • setXxx()方法
  • 构造方法

案例演示

public class Teacher {
    //一个类的组成:构造方法、成员变量、成员方法
    //私有成员变量
    private String name;
    private int age;
    //提供有参、无参构造
    public Teacher() {

    }
    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //提供公共的 get set 方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class MyTest {
    public static void main(String[] args) {
        //使用空参构造来创建对象
        Teacher teacher = new Teacher();
        //set方法给成员变量赋值
        teacher.setName("张三");
        teacher.setAge(18);
        System.out.println(teacher.getName());
        System.out.println(teacher.getAge());
        //使用有参构造来创建对象,在创建对象的同时,就可以给成员变量赋值
        Teacher teacher1 = new Teacher("李四", 35);
        System.out.println(teacher1.getName());
        System.out.println(teacher1.getAge());
    }
}

在这里插入图片描述

九、创建一个对象的完整步骤

(1)加载.class文件进内存
(2)在栈内存为创建对象的变量开辟空间
(3)在堆内存为对象开辟空间
(4)给对象的成员变量进行默认初始化
(5)给对象的成员变量进行显式初始化
(6)通过构造方法给对象的成员变量赋值
(7)对象初始化完毕,把对象地址赋值给变量

案例演示

public class Student {
    private String name="张三";
    private int age=10;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class MyTest {
    public static void main(String[] args) {
        Student s = new Student("王五", 25);
        //(1)加载Student.class文件进内存
		//(2)在栈内存为s开辟空间
		//(3)在堆内存为学生对象开辟空间
		//(4)对学生对象的成员变量进行默认初始化
		//(5)对学生对象的成员变量进行显式初始化
		//(6)通过构造方法对学生对象的成员变量赋值
		//(7)学生对象初始化完毕,把对象地址赋值给s变量
    }
}

在这里插入图片描述


练习
定义一个长方形(Rectangle)类,定义求周长和求面积的方法,然后定义一个测试类,进行测试。

public class Rectangle {
    private double length;
    private double width;

    public Rectangle(double length,double width){//有参构造
        this.length=length;
        this.width=width;
    }
    public double getPerimeter(){//求周长
        return 2*length+2*width;
    }
    public double getArea(){//求面积
        return length*width;
    }
}
public class RectangleDemo {
    public static void main(String[] args){
        Rectangle rectangle = new Rectangle(2.5, 4.2);
        System.out.println("周长为:"+rectangle.getPerimeter());
        System.out.println("面积为:"+rectangle.getArea());
    }
}

在这里插入图片描述

十、static关键字

(一)static关键字的引入

案例

public class Person {
    public String name;
    //我想定义一个全是中国人的类
    //我想让中国这个数据变成共享变量,让这个类的所有对象,都能够共享它
    //我们可以使用一个关键字,static 静态的 可以修饰成员变量和成员方法
    //被static所修饰的成员变量,是一个共享变量,被类的所有对象所共享
    //被static所修饰的成员叫作静态成员,它随着类的加载而加载(随着.class文件加载进内存,静态成员就会加载)
    //静态成员优先于对象而存在
    public static String country = "中国";
}
public class MyTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.name="张三";
        person.country="美国";

        Person person2 = new Person();
        person2.name = "李四";
        person2.country = "新加坡";//因为静态成员变量共享,所以修改它,每个对象的该成员变量同时改变

        System.out.println(person.name+"----"+person.country);
        System.out.println(person2.name + "----" + person2.country);
    }
}

在这里插入图片描述
在这里插入图片描述
注意:类一加载,静态成员就存在了。(静态成员随着类的加载而加载)

(二)static关键字的特点

(1)随着类的加载而加载
(2)优先于对象存在
(3)被类的所有对象共享
举例:一个班级的学生应该共用同一个班级编号。
其实这个特点也是在告诉我们什么时候使用静态
如果某个成员变量是被所有对象共享的,那么它就应该定义为静态的。
(4)可以通过类名调用
其实它本身也可以通过对象名调用,但推荐使用类名调用。
静态修饰的内容一般我们称其为:与类相关的、类成员

案例演示

public class MyTest {
    public static void main(String[] args) {
        //A a = new A();
        //int b = a.b;
        //通过 对象名.共享变量名 这种方式,去访问共享变量不报错,但不推荐使用

        //被static 所修饰的我们推荐使用类名直接调用
        //因为静态变量,属于类,所以使用类名直接调用即可
        A.b=500;
        int b = A.b;
        System.out.println(b);
        //a.show(); 不推荐使用
        A.show();//静态方法,推荐使用类名直接调用
    }
}
class A{
    int a=100;
    static int b=1000; //静态变量(共享变量)
    public static void show(){//静态方法
        System.out.println("这是一个静态的show方法");
    }
}

(三)static的注意事项

(1)在静态方法中是没有this关键字的
如何理解呢?
静态是随着类的加载而加载的,this是随着对象的创建而存在的。
因此,静态比对象先存在。
(2)静态方法只能访问静态成员变量和静态成员方法;而非静态方法不仅可以访问静态成员变量和静态成员方法,还能访问非静态成员变量和非静态成员方法。
简单记:静态只能访问静态,非静态可以访问静态的也可以访问非静态的。

案例演示

public class MyTest {
    public static void main(String[] args) {
    }
}
class B{
    int a=10;
    static double num=100;

    //非静态方法,既可以访问静态变量,也可以访问非静态变量
    public void show(){
        System.out.println(a);
        System.out.println(num);
    }
    //静态方法
    public static void staticShow(){
        //System.out.println(a);报错,不能访问非静态变量
        System.out.println(num);
    }
    //非静态方法,既可以访问静态方法,也可以访问非静态方法
    public void test() {
       this.show();
       staticShow();
    }
    //静态方法,只能访问静态方法
    public static void test2() {
        //show();报错
        //this.staticShow();报错
        //静态方法里面,不能存在this,this代表一个对象,对象是后来才有的,先有的,不能访问后有的
        staticShow();
    }
}

注意:main方法也是静态方法,main方法中调用的方法也必须得是静态方法,否则无法直接调用。

(四)静态变量和成员变量的区别

(1)所属不同
静态变量属于类,所以也称为类变量
成员变量属于对象,所以也称为实例变量(对象变量)
(2)内存中位置不同
静态变量存储于方法区中的静态区
成员变量存储于堆内存
(3)内存出现时间不同
静态变量随着类的加载而加载,随着类的消失而消失
成员变量随着对象的创建而存在,随着对象的消失而消失
(4)调用不同
静态变量可以通过类名调用,也可以通过对象调用(不推荐)
成员变量只能通过对象名调用


拓展:Math类的随机数功能

(一)Math类概述

Math类包含用于执行基本数学运算的方法

(二)Math类特点

由于Math类在java.lang包下,所以不需要导包。
没有构造方法,因为它的成员全部是静态的(可以直接用类调用方法,不需要创建对象)。

(三)获取随机数的方法

public static double random();返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。

案例演示
获取十个1-100之间的随机整数(包括1和100)

public class MyTest {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
        	//直接用类调用方法
            int num=(int)(Math.random()*100+1);//强制转换为整型
            System.out.println(num);
        }
    }
}

在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值