今天我们来看构造方法
构造方法
什么是构造方法?下面来看
概念
构造方法的目的是为对象中的数据进行初始化。
格式
1.方法名字和类名相同
2.没有返回值类型,连void都没有
3.没有具体的返回值
class Student {
private String name;
private int age;
Student(){
System.out.println("这是无参的构造方法");
}
//getXxx()和setXxx()方法
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public void show() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class StructureDemo1 {
public static void main(String[] args) {
//创建对象
Student s = new Student();
s.show();
}
}
思考:
我们在学习构造方法之前,也是new对象出来,现在知道了,内部一直都是调用一个无参的构造方法,但是呢,我们在类中并没有区写出来构造方法,所以问题是我们一直用的构造的方法来自哪里呢?
注意哦:
1.如果我们没有给出构造方法,jvm就会自动的提供一个无参的构造方法给我们。
2.如果我们给出了构造方法,jvm就不会再提供默认的无参的构造方法了。
如果我们没有给出无参的构造方法,却给出了其他的构造方法,jvm就不再提供默认的构造方法
只要我们给出了构造方法,无论是有参的还是无参,jvm就用永远不会再提供午无参的构造方法。
3.构造在同一个类的也是可以发生重载的。(方法名一样,参数列表不一样,与返回值无关。)
作用
可以在创建对象的时候给对象的成员变量进行赋值。
现在我们学习了两种给成员对象赋值的方法了:
- 使用类提供的公共的setXxx()方法给成员变量进行赋值。
- 使用代参数的构造方法给私有的成员变量进行赋值。
注意:形参的变量名和成员名一样的时候,需要this关键字一起使用。
接下来代码练习:
class Structure {
private String name;
private int age;
Structure() {
System.out.println("这是我们自己写的无参构造方法");
}
Structure(String name) {
System.out.println("这是我们自己写的带name参数的带参构造方法");
this.name = name;
}
Structure(int age){
System.out.println("这是我们自己写的带age参数的带参构造方法");
this.age = age;
}
Structure(String name,int age){
System.out.println("这是我们自己写的带所有成员变量的参数的带参构造方法");
this.name = name;
this.age = age;
}
public void show() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class StructureDemo2 {
public static void main(String[] args) {
Structure s1 = new Structure();
//能看到地址值说明咱们的对象已经被new了出来
System.out.println(s1);
System.out.println("=======================");
//创建第二个对象
Structure s2 = new Structure("李玉伟");
s2.show(); //李玉伟,0
System.out.println("=======================");
//创建第三个对象
Structure s3 = new Structure(17);
s3.show();//null,17
System.out.println("=======================");
//创建第四个对象
Structure s4 = new Structure("kayleigh",18);
s4.show();
}
}
构造方法就先看看到这,下面我们来看新的内容:我们用一个例子来引出这个内容
定义一个人的类
经过测试发现,我们举例子的时候,都是中国人,国籍都一样,都是中国,一样的国籍,每次创建的时候,都会在堆内存开辟一个这样的变量空间,总觉得有点浪费。有没有什么办法,让所有一样国籍的人共用一个国籍的值,针对多个对象拥有共同的成员变量,值是一样的时候
Java提供了一个关键字给我们处理这样的情况,这个关键字叫做:static
可以修饰成员变量和成员方法,修饰成员变量的时候,可以让多个对象共用一个成员变量的值。
class Person{
//姓名
private String name;
//年龄
private int age;
//国籍
// private String nationality;
private static String nationality;
public Person() {
}
public Person(String name, int age, String nationality) {
this.name = name;
this.age = age;
this.nationality = nationality;
}
public Person(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 String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public void show(){
System.out.println("姓名:"+name+",年龄:"+age+",国籍:"+nationality);
}
}
public class PersonDemo {
public static void main(String[] args) {
//创建第一个对象
Person p1 = new Person("kayleigh",26,"中国");
p1.show();
//创建第二个对象
Person p2 = new Person("kaylemon",30);
p2.show();
//创建第三个对象
Person p3 = new Person("kaylele",18);
p3.show();
System.out.println("==========================================");
// p1.setNationality("俄罗斯");
// p1.show();
// p2.show();
// p3.show();
//这里可以把注释去掉,可以看看输出的内容有什么不一样。
}
}
注意一下,这里的重置默认的国籍,就会更改全部的成员变量的国籍值。
下面我们正式来看一下static关键字的作用和用途。
static关键字
特点
- 随着类的加载而加载。
运行之前会将calss类文件加载到方法区,而被static修饰的成员是随着类的加载而加载,所以static修饰的成员在方法区里面存放。 - 优先于对象存在。
- 被类所有的对象共享。
举例:所有的中国人的国籍信息都一样什么时候使用static关键字呢?如果说明某个成员变量是被所有对象共享的,那么它就应该被定义为静态的。
举例:
哈罗单车:(可以被static修饰)
自己的水杯:(不可以被static修饰) - 被静态修饰的成员可以直接通过类名调用。
一般情况下,我们今后开发的时候,只要看到类中有静态的成员变量或者成员方法,今后在调用的时候,一律用 类名.静态成员 这样的方法调用。
推荐使用类名的方法调用,这也是规范。
通过调用的方式区分不同的成员。
所以被静态修饰的成员,一般情况下称之为:类成员,与类相关。
class Demo2{
//定义一个非静态的成员变量
int a = 10;
//定义一个静态的成员变量
static int b = 20;
}
public class StaticDemo1 {
public static void main(String[] args) {
Demo2 d1 = new Demo2();
System.out.println(d1.a);
System.out.println(d1.b);
//这里可以看到可以直接被调用。
System.out.println(Demo2.b);
}
}
下面我们来看看静态成员访问的问题
1、static可以修饰成员变量和成员方法。
2、非静态成员方法:
1)访问的是非静态的成员变量
可以
2)访问的是静态的成员变量
可以
3)访问的是非静态的成员方法
可以
4)访问的是静态的成员方法
可以
总结:非静态的成员方法可以访问静态的成员也可也访问非静态的成员
静态的成员方法:
1)访问的是非静态的成员变量
不可以
2)访问的是静态的成员变量
可以
3)访问的是非静态的成员方法
不可以
4)访问的是静态的成员方法
可以
总结:静态的成员方法只能访问静态的成员
class Demo3{
//非静态的成员变量
int a = 10;
//静态的成员变量
static int b = 20;
//非静态的成员方法
public void fun1(){
System.out.println(a);
System.out.println(b);
fun2();
fun3();
}
public static void fun2(){
//Error:(47, 28) java: 无法从静态上下文中引用非静态 变量 a
// System.out.println(a);
// System.out.println(b);
// System.out.println("这是静态的成员方法fun2");
//Error:(51, 9) java: 无法从静态上下文中引用非静态 方法 fun3()
// fun3();
fun4();
}
public void fun3(){
System.out.println("这个是非静态的成员方法fun3");
}
public static void fun4(){
System.out.println("这是静态的成员方法fun4");
}
}
public class StaticDemo2 {
public static void main(String[] args) {
Demo3 d = new Demo3();
// d.fun1();
Demo3.fun2();
fun();
}
public static void fun(){
System.out.println("helloworld");
}
}
我们来做做练习:
/*
标准类代码3.0版本,一个标准的手机类
分析:
手机:
属性:品牌,颜色,价格
行为:打电话,发短信,学习
类:
成员变量:brand,color,price(使用private修饰)
构造方法:无参构造方法,带参构造方法
成员方法:setXxx()和getXxx()方法
show():输出所有的成员变量
*/
public class Phone {
//定义成员变量
private String brand;
private String color;
private int price;
//定义构造方法
Phone() {
}
Phone(String brand, String color, int price) {
this.brand = brand;
this.color = color;
this.price = price;
}
//定义公共的setXxx()和getXxx()
public void setBrand(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void setPrice(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
//定义一个可以输出所有成员变量的方法
public void show() {
System.out.println("品牌:" + brand + ",颜色:" + color + ",价格:" + price);
}
}
/*
手机测试类:
开发中最常用的是第二种方式,单个使用永远要比混合使用要灵活
*/
public class PhoneDemo {
public static void main(String[] args) {
//使用无参的构造方法创建对象,并使用setXxx()给成员变量进行赋值
System.out.println("=======使用无参的构造方法创建对象,并使用setXxx()给成员变量进行赋值=======");
Phone p1 = new Phone();
System.out.println("未赋值前:");
p1.show();
p1.setBrand("华为");
p1.setColor("黑色");
p1.setPrice(4999);
System.out.println("赋值后:");
p1.show();
System.out.println("================================================");
System.out.println("=======使用带参数的构造方法创建对象,并使用getXxx()获取成员变量=======");
Phone p2 = new Phone("锤子手机","白色",8888);
String brand = p2.getBrand();
String color = p2.getColor();
int price = p2.getPrice();
System.out.println("品牌["+brand+"]\t颜色["+color+"]\t价格["+price+"]");
}
}
package com.bigdata.day12;
/*
定义一个类Demo,其中定义一个求两个数据和的方法,定义一个测试了Test,进行测试。
*/
class Demo {
//第一种方式:
// public int sum() {
// int a = 11;
// int b = 22;
// int c = a + b;
// return c;
// }
//第二种方式:
//通过第一种方式实现了我们题目的需求
//但是不好,因为加法的数值写固定了,所以不好
//改进:可以将来传两个值进来
public int sum(int x, int y) {
return x + y;
}
//第二种方式对然相比较于第一种方式来说,虽然我们可以进行手动传入参数,但是
//实现的过程并没有用到面向对象的封装的知识
//我们可以尝试将两个参数定义为成员变量
//第三种方式:
// private int a;
// private int b;
//
// public int sum(int a,int b){
// this.a = a;
// this.b = b;
// return (this.a+this.b);
// }
//问题:哪一种方式实现该问题的最优解?
//其实,我们在面对业务问题的时候,什么时候考虑使用面向对象的思想
//或者换句话说,什么情况下,将我们问题中的参数定义成成员变量呢?
//只有当我们题目中参数与该类形成属性和行为的关系的时候,才定义成成员变量
//因为类是用来描述现实世界事物的,
//所以也就说成员变量是用来描述类
//所以,这道题,第二种方式是最优解。
}
public class Test1 {
public static void main(String[] args) {
//创建对象
Demo d = new Demo();
int sum = d.sum(65,70);
System.out.println(sum);
}
}
package com.bigdata.day12;
/*
定义一个员工类,自己分析出几个成员,
然后给出成员变量,构造方法,getXxx()/setXxx()方法,
以及一个显示所有成员信息的方法。并测试。
员工:
属性:工号,姓名,年龄,薪水
行为:敲代码,吃饭,喝水
*/
class Staff {
private String id;
private String name;
private int age;
private int salary;
Staff() {
}
Staff(String id, String name, int age, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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 int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
//以及一个显示所有成员信息的方法
public void show() {
System.out.println("工号:" + id + ",姓名:" + name + ",年龄:" + age + ",薪水:" + salary);
}
}
public class Test3 {
public static void main(String[] args) {
//使用带参数的构造方法创建对象
Staff s = new Staff("SJ005","王友虎",18,1000000);
s.show();
}
}
package com.bigdata.day12;
/*
定义一个类MyMath,提供基本的加减乘除功能,然后进行测试
导包import语句在所有的class之前
*/
import java.util.Scanner;
class MyMath {
//加法功能
public int add(int a, int b) {
return a + b;
}
//减法功能
public int sub(int a, int b) {
return a - b;
}
//乘法功能
public int mul(int a, int b) {
return a * b;
}
//除法功能
public double div(int a, int b) {
return (a * 1.0) / b;
}
}
public class Test4 {
public static void main(String[] args) {
MyMath compute = new MyMath();
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个数据num1:");
int num1 = sc.nextInt();
System.out.println("请输入第二个数据num2:");
int num2 = sc.nextInt();
System.out.println("num1+num2=" + compute.add(num1, num2));
System.out.println("num1-num2=" + compute.sub(num1, num2));
System.out.println("num1*num2=" + compute.mul(num1, num2));
System.out.println("num1/num2=" + compute.div(num1, num2));
}
}