欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA面向对象进阶

程序员文章站 2024-02-18 18:17:28
...

构造方法

构造方法概述
  • 构造方法概述和作用
    a. 创建对象,给对象中的成员进行初始化
    b. 构造函数(方法) : 我们在创建对象时,除了使用关键字new之外,还有调用构造方法来完成对类的实例化。(创建对象时, Student st = new Student() 感觉像是在调用一个函数,从而猜想应该有一个函数,即:构造函数!)
  • 构造方法格式特点
    a. 方法名与类名相同
    b. 没有返回值类型,连void都没有
    c. 没有具体的返回值
  • 构造方法的一些细节性的描述:
    a. 我们自定义的类,默认存在一个空(无)参数的构造方法。(系统将自动提供一个无参构造方法。)
    b. 构造方法的语法:方法名与类名相同,没有返回值,也没有void等进行定义返回值类型。
    c. 构造函数是必须被调用的,如果构造函数被private修饰,则该类的对象无法进行实例化。
构造函数的方法重载:
  • 是什么?
    能做很多事,比如定义多个参数类型或个数的构造函数,实例化对象可以传递不同的参数进行实例化,顺便将其成员变量的相应数值就进行设置了!
  • 特殊
    一个创建出来的类模式有一个无参构造函数的,如果手动给出类的一个有参构造,那么默认无参构造就没有了,如果你还想使用无参构造创建对象,建议你手动写出无参构造,才能进行无参数构造来创建对象(这里也用到了构造函数的重载)
  • 建议:
    a. 永远自己给出无参构造方法
    b. 给出有参构造方法(如果需要的话!)
  • 给成员变量赋值的两种方式
    a. setXxx()方法
    b. 构造方法
  • 示例:
    public class Cat {
        private String name;
        private int age;
        public Cat(){
            System.out.println("无参构造调用了");
        }
        public Cat(String name,int age){
            System.out.println("有参构造调用了"+name+"==="+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) {
            Cat cat = new Cat();
            //借助set方法给成员变量设置值
            cat.setName("汤姆");
            cat.setAge(20);
            System.out.println(cat.getName());
            System.out.println(cat.getAge());
            System.out.println("-----------------------");
            //采用有参构造,给成员变量设置值
            Cat cat1 = new Cat("加菲猫", 2);
            System.out.println(cat1.getName());
            System.out.println(cat1.getAge());
        }
    }
    ------------------------------
    输出:
    无参构造调用了
    汤姆
    20
    -----------------------
    有参构造调用了加菲猫===2
    加菲猫
    2
    
  • 构造方法不用调用到栈中去吗?
  • 那如果调用set,get等方法会进栈吗?(理论上来说:一定会!)
  • 构造函数前不能加static关键字!(编译器报错!)

创建一个对象的步骤:

  • 画图说明一个对象的创建过程做了哪些事情?
    Student s = new Student();
    • 图示:JAVA面向对象进阶
    • 步骤:
      (1):加载Student.class文件进内存
      (2):在栈内存为s开辟空间
      (3):在堆内存为学生对象开辟空间
      (4):对学生对象的成员变量进行默认初始化
      (5):对学生对象的成员变量进行显示初始化
      (6):通过构造方法对学生对象的成员变量赋值
      (7):学生对象初始化完毕,把对象地址赋值给s变量
  • 案例演示:
    a. 定义一个长方形(Rectangle)类,定义求周长(length)和面积(area)的方法,
    b. 然后定义一个测试类Test,进行测试。
    • 代码:
    public class Rectangle {
    	//成员属性
        private double width;
        private double height;
        //提供无参,有参构造
    
        public Rectangle() {
        }
    
        public Rectangle(double width, double height) {
            this.width = width;
            this.height = height;
        }
        //提供get set 方法
    
        public double getWidth() {
            return width;
        }
    
        public void setWidth(double width) {
            this.width = width;
        }
    
        public double getHeight() {
            return height;
        }
    
        public void setHeight(double height) {
            this.height = height;
        }
    
        //提供获取周长的方法
        public double getLength() {
    
            return (this.width + this.height) * 2;
        }
    
        //提供获取面积的方法
        public double getArea() {
            return height * width;
        }
    
    }
    
    主函数:
    public class MyTest {
        public static void main(String[] args) {
            Rectangle rectangle = new Rectangle();
            rectangle.setWidth(20);
            rectangle.setHeight(30);
            double area = rectangle.getArea();
            double length = rectangle.getLength();
            System.out.println("面积是:"+area);
            System.out.println("周长是:"+length);
    
            System.out.println("--------------------------");
            Rectangle rectangle1 = new Rectangle(60, 30);
            double area1 = rectangle1.getArea();
            double length1 = rectangle1.getLength();
    
            System.out.println("面积是:" + area1);
            System.out.println("周长是:" + length1);
    
        }
    }
    ----------------------------
    输出:
    面积是:600.0
    周长是:100.0
    --------------------------
    面积是:1800.0
    周长是:180.0
    

static关键字的引入

  • 示例:
    public class Person {
        public String name;
        //static 静态的:可以修饰成员变量,成员方法,修饰成员变量,此变量就变成了共享变量
        public static  String guoji="中国";
    }
    
    主函数:
    public class MyTest {
        public static void main(String[] args) {
            //我想并把中国这个 数据,设置成共享数据,让多个对象,去共享这个数据
            Person.guoji="英国";
            //被静态所修饰的成员,属于类的 推荐使用类名直接调用
            //被static所修饰的成员变量,我们称之为类变量
    
            Person p1 = new Person();
            p1.name = "张三";
           // p1.guoji = "美国";
    
    
            Person p2 = new Person();
            p2.name = "李四";
            //p2.guoji = "中国";
    
    
            Person p3 = new Person();
            p3.name = "王五";
            // p3.guoji = "中国";
    
    
            System.out.println(p1.name);
            System.out.println(p1.guoji);
    
    
            System.out.println(p2.name);
            System.out.println(p2.guoji);
    
    
            System.out.println(p3.name);
            System.out.println(p3.guoji);
        }
    }
    --------------------------------
    输出:
    张三
    英国
    李四
    英国
    王五
    英国
    
    更改主函数为:
    public class Test {
        public static void main(String[] args) {
            //我想并把中国这个 数据,设置成共享数据,让多个对象,去共享这个数据
            Person.guoji = "英国";
            //被静态所修饰的成员,属于类的 推荐使用类名直接调用
            //被static所修饰的成员变量,我们称之为类变量
    
            Person p1 = new Person();
            p1.name = "张三";
            p1.guoji = "美国";
    
    
            Person p2 = new Person();
            p2.name = "李四";
            p2.guoji = "意大利";
    
    
            Person p3 = new Person();
            p3.name = "王五";
            // p3.guoji = "中国";
    
    
            System.out.println(p1.name);
            System.out.println(p1.guoji);
    
    
            System.out.println(p2.name);
            System.out.println(p2.guoji);
    
    
            System.out.println(p3.name);
            System.out.println(p3.guoji);
        }
    }
    ----------------------------------------------------
    输出:
    张三
    意大利
    李四
    意大利
    王五
    意大利
    
    • 结论: 由此我们得到了一个结论,属于类变量的变量其实内存是在代码区的。当这个类被引入的时候就已经存在于内存了(尽管此时还未经历初始化),堆内存中的对象其中的某个成员变量(现在叫做类变量)都是指向这个代码区的内存的。所以:类变量的所有该类对象所共有的,一旦一个对象对其操作,就相当于改变了代码区中该变量的数值,因为其他该类对象也指向这里,所以其他对象该变量的数值也都发生了变化。
  • 画图演示: 带有static的内存图(待补充!)
  • static关键字的特点:
    a. 随着类的加载而加载
    b. 优先于对象存在
    c. 被类的所有对象共享
        实这个特点也是在告诉我们什么时候使用静态?
        如果某个成员变量是被所有对象共享的,那么它就应该定义为静态的。
        举例:
            饮水机(用静态修饰)
            水杯(不能用静态修饰)
    d. 可以通过类名调用
        其实它本身也可以通过对象名调用。
        推荐使用类名调用。
        静态修饰的内容一般我们称其为:与类相关的,类成员
  • static的注意事项:
    a. 在静态方法中是没有this关键字的
        如何理解呢?
            静态是随着类的加载而加载,this是随着对象的创建而存在。
            静态比对象先存在。
    b. 静态方法只能访问静态的成员变量和静态的成员方法
    简单记:静态只能访问静态,非静态可以访问静态的也可以访问非静态的
static 小结
  • static 静态的:可以修饰成员变量,成员方法,修饰成员变量,这个成员变量就是共享的了。(放在了常量池中?即:静态修饰后的变量在代码区就已经生成了并且完成了赋值)
  • 被静态修所修饰的成员,属于类的 推荐使用类名直接调用
  • 被static所修饰的成员,已经变成了类变量,在类被加载的时候,就已经完成类初始化
  • 实例变量被实例(对象)调用,类变量推荐使用类进行直接调用(不推荐使用对象进行调用)
  • static 不仅可以修饰成员变量还可以修饰成员方法。
  • static 修饰过后的成员变量或者方法,都不用需要对象来调用,直接用类名调用就OK了,而且不需要对类进行实例化。
  • 加载时机的问题(static 修饰的方法随着类加载就已经加载了,所以在static修饰的方法中不能用类的成员变量,但可以用类变量,因为此时类的成员变量还不存在,new了对象以后类成员变量才存在,所以类加载时需要将static修饰的方法加载到方法区中的静态区,此时static修饰的方法中不允许存在类的成员变量)
  • 静态只能调用静态,非静态既能调用静态也能调用非静态
  • 在非静态方法中不能使用this
  • 经典例题:(重点理解!)
    public class Test {
        static int total = 10;
    
        public static void main(String[] args) {
            new Test();
            new Test();
        }
    
        public Test() {
            int temp = this.total;
            if (temp++ > 5) {
                this.total += temp;
                System.out.println(temp);
            }
     	}
    }
    --------------------------------
    输出:
    11
    22
    
静态变量和成员变量的区别:
  • 所属不同
    a. 静态变量属于类,所以也称为类变量
    b. 成员变量属于对象,所以也称为实例变量(对象变量)
  • 内存中位置不同
    a. 静态变量存储于方法区的静态区
    b. 成员变量存储于堆内存
  • 内存出现时间不同
    a. 静态变量随着类的加载而加载,随着类的消失而消失
    b. 成员变量随着对象的创建而存在,随着对象的消失而消失
  • 调用不同
    a. 静态变量可以通过类名调用,也可以通过对象调用,推荐使用类名调用
    b. 成员变量只能通过对象名调用

JDK提供的帮助文档

如何使用JDK提供的帮助文档?

A. 找到文档,打开文档
B. 点击显示,找到索引,出现输入框
C. 你应该知道你找谁?举例:Scanner
D. 看这个类的结构(需不需要导包)

  • java.lang包下的内容不需要我们手动导入
  • 其它包下的内容需要我们手动导入
  • 文档中的对应内容:
名称 对应内容
API文档
成员变量 字段摘要
构造方法 构造方法摘要
成员方法 方法摘要

E. 看这个类的说明(简单的了解一下)
F. 看开始版本
G. 看构造方法
H. 看成员方法

  • 看左边:
         是否是static的,如果是我们就不需要创建对象,直接可以使用类名调用该方法;看返回值类型,返回值是什么类型,我就使用什么类型声明的变量来接收。
  • 看右边:
         看参数列表: 参数的个数 , 参数的类型 ; 它需要什么参数使用的时候,就传递什么参数即可。

i. 然后使用

JDK帮助文档使用实践:学习Math类的随机数功能
  • Math类概述:
    类包含用于执行基本数学运算的方法
  • Math类特点:
    a. 由于Math类在java.lang包下,所以不需要导包。
    b. 没有构造方法,因为它的成员全部是静态的。
  • 获取随机数的方法:
    public static double random() 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
  • 我要获取一个1-100之间的随机数,肿么办?
    int number = (int)(Math.random()*100)+1
    
使用math进行一次猜数游戏:
  • 示例:
    public class Test{
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int num = (int)(Math.random()*100+1);
            System.out.println("请你输入一个 0~100 之间的数字:");
            int input_num = scanner.nextInt();
            int count = 9;
            while (count >= 0){
                if (input_num > num){
                    System.out.println("您输入的数字偏大了!您的剩余机会还有"+count--);
                }else if (input_num < num){
                    System.out.println("您输入的数字偏小了!您的剩余机会还有"+count--);
                }else {
                    System.out.println("您猜测对了!总共使用了"+(10-count)+"次机会");
                    break;
                }
                System.out.println("请你输入一个 0~100 之间的数字:");
                input_num = scanner.nextInt();
            }
            if(count<0){
                System.out.println("您的猜测机会已经用完了!");
            }
        }
    }
    ------------------
    输出:
    请你输入一个 0~100 之间的数字:
    50
    您输入的数字偏大了!您的剩余机会还有9
    请你输入一个 0~100 之间的数字:
    25
    您输入的数字偏大了!您的剩余机会还有8
    请你输入一个 0~100 之间的数字:
    13
    您输入的数字偏大了!您的剩余机会还有7
    请你输入一个 0~100 之间的数字:
    6
    您输入的数字偏小了!您的剩余机会还有6
    请你输入一个 0~100 之间的数字:
    10
    您输入的数字偏小了!您的剩余机会还有5
    请你输入一个 0~100 之间的数字:
    12
    您输入的数字偏大了!您的剩余机会还有4
    请你输入一个 0~100 之间的数字:
    11
    您猜测对了!总共使用了7次机会
    

代码块

  • 代码块概述:
    在Java中,使用{}括起来的代码被称为代码块。
  • 代码块分类:
    根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
  • 常见代码块的应用:
    a. 局部代码块
         在方法中出现;限定变量生命周期,及早释放,提高内存利用率
    b. 构造代码块
         在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
    c. 静态代码块 (注意静态只能调用静态!)
         在类中方法外出现,并加上static修饰;用于给类进行初始化,在类加载的时候就执行,并且只执行一次。
  • 看程序写结果(经典例题)
    class Student {
    	static {
    		System.out.println("Student 静态代码块"); //3
    	}
    	
    	{
    		System.out.println("Student 构造代码块"); //4 6
    	}
    	
    	public Student() {
    		System.out.println("Student 构造方法"); //5 7
    	}
    }
    
    class StudentDemo {
    	static {
    		System.out.println("StudentDemo的静态代码块");  //1
    	}
    	
    	public static void main(String[] args) {
    		System.out.println("我是main方法"); //2 
    		
    		Student s1 = new Student();
    		Student s2 = new Student();
    	}
    }
    ----------------------------
    输出:
    StudentDemo的静态代码块
    我是main方法
    Student 静态代码块
    Student 构造代码块
    Student 构造方法
    Student 构造代码块
    Student 构造方法