小言_互联网的博客

JAVA面向对象进阶

267人阅读  评论(0)

构造方法

构造方法概述
  • 构造方法概述和作用
    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();
    • 图示:
    • 步骤:
      (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 构造方法
    

转载:https://blog.csdn.net/weixin_35995730/article/details/102486446
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场