一、构造方法(封装)
1构造方法的定义和使用
Person p = new Person();
1)构造方法:构造函数,构造器,Constructor
2)构造方法的作用:
为对象中的成员变量进行赋值,当创建对象同时,构造方法主动调用
等对象创建完毕,对象中的成员变量就有值了
3)构造方法定义语法结构:
修饰符 构造方法名(参数列表){
方法体;// 通常使用构造进行成员变量的赋值
}
4)解释:
1) 修饰符 : 通常使用public 公共的修饰
2) 构造方法没有返回值类型, 连void都不写
3) 构造方法名必须与类型保持一致,连大小写都必须一样
4) 因为构造没有返回值类型,因此构造中可以没有return, 如果一定要写, return;
5)构造方法的运行机制:
每次创建对象, 构造方法会被JVM虚拟机主动调用一次, 构造方法不能被对象名.手动调用
举例
public class Person { // 定义出私有成员变量 private String name; private int age; // 定义出一个构造,为了给成员变量进行赋值 public Person() { name = "张三"; age = 20; System.out.println("我是空参数构造,我执行了"); } public void setName(String name) { this.name = name; } public String getName() { return name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class TestPerson { public static void main(String[] args) { // 1. 空参数构造的调用 Person p = new Person(); System.out.println(p.getName()); System.out.println(p.getAge()); // 构造方法无法被手动调用 // p.Person(); Person p1 = new Person(); Person p2 = new Person(); } }
2 构造方法使用的注意事项
- 构造方法的参数列表:
1) 构造方法可以没有参数, 创建对象同时,()中就是空的, 只能在构造方法中给成员变量赋值默认值
2) 构造方法可以有参数, 创建对象同时, ()中需要提供构造实际参数, 可以通过参数列表给成员变量进行赋值
2.如果类中,没有定义任何的构造方法,那么系统自动为类型创建出一个空参数的构造方法,空参数构造使用 public修饰, 构造方法中,没有任何逻辑
3.如果类中, 已经手动定义了构造方法(不论构造有无参数列表), 那么系统不会自动添加任何构造
4.构造方法可以重载:
定义在同一个类中, 方法名相同, 方法的参数列表不同, 与方法的返回值类型无关,多个方法之间,称为方法重载(Overload)
1) 构造方法名全部与类名一致, 方法名相同
2) 方法的参数列表不同 : 自己把握
3) 与方法的返回值类型无关 : 构造方法没有返回值类型
代码
public class Person { // 定义出私有成员变量 private String name; private int age; // 定义出一个构造,为了给成员变量进行赋值 public Person() { name = "张三"; age = 20; System.out.println("我是空参数构造,我执行了"); } // 定义出一个构造,通过构造方法参数列表给成员变量进行赋值 public Person(String name, int age) { this.name = name; this.age = age; System.out.println("我是有参数构造,执行了~~~~~~~~~~"); } public void setName(String name) { this.name = name; } public String getName() { return name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }
public class TestPerson { public static void main(String[] args) { // 1. 空参数构造的调用 //The constructor Person() is undefined Person p = new Person(); System.out.println(p.getName()); System.out.println(p.getAge()); // 构造方法无法被手动调用 // p.Person(); Person p1 = new Person(); Person p2 = new Person(); // 2. 有参数构造调用,需要创建对象同时,传递实际参数 Person p3 = new Person("小花",19); System.out.println(p3.getName()); System.out.println(p3.getAge()); Person p4 = new Person("QQ",17); System.out.println(p4.getName()); System.out.println(p4.getAge()); // 3. 如果类型中,没有定义任何的构造方法,那么系统自动为类型创建出一个空参数的构造方法 // 空参数构造使用 public修饰, 构造方法中,没有任何逻辑 Person p5 = new Person(); }
3.this关键字在构造方法中的使用
- 构造方法之间,可以互相调用
使用this(被调用的构造实际参数) , 可以调用另外一个构造方法、
2.this() 本类构造方法之间的调用 : 要求this()必须放在构造方法有效行第一行
3.总结this关键字的使用
1) this关键字用于区分成员变量和局部变量重名问题, 带有this关键字的变量表示成员变量的使用
2) this() : 表示本类构造之间的调用, ()需要传递实际参数, this()必须在构造方法有效行第一行
代码
public class ThisAndCon { private String name; private int age; // 1. 定义出一个空参数构造 public ThisAndCon() { System.out.println("空参数构造"); } // 2. 定义出一个有参数构造 public ThisAndCon(String name, int age) { // this()表示调用空参数构造 // this(); // this(name) : 表示有参数构造调用 this("小美");//Constructor call must be the first statement in a constructor // this.name = name; this.age = age; System.out.println("有参构造执行了"); } // 3. 定义出一个有参数构造 public ThisAndCon(String name) { this.name = name; System.out.println("给name赋值"); } 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 TestThis关键字在构造中的使用 { public static void main(String[] args) { ThisAndCon tac = new ThisAndCon("小花",25); System.out.println(tac.getName()); System.out.println(tac.getAge()); }
4.构造方法和set赋值比较
构造方法无法取代set方法给成员变量赋值过程
1.构造只能在创建对象同时,给对象中的成员变量进行一次赋值,无法通过构造改值
2.set赋值 : 发生在创建对象之后, 使用对象名.调用set方法给对象中的成员变量进行赋值, 方法可以多次调用,每次调用都可以修改对象中成员变量的值
5.创建对象给成员变量赋值的过程
- 创建一个对象时, 给这个对象的成员变量赋值,有3种方式:
1) JVM虚拟机默认赋值
2) 成员变量的显示赋值
3) 构造方法赋值
2.三种方式赋值过程:
1) 首先将对象的成员变量加载进堆内存中, JVM虚拟机进行默认的赋初值动作
2) 如果成员变量有显示赋值(定义成员变量时, 直接赋值). 显示赋值覆盖掉JVM虚拟机赋值
3) 如果有构造方法赋值, 那么构造赋值覆盖掉显示赋值, 最终以构造赋值为标准
代码
public class 对象创建成员赋值过程 { // 姓名 String name; // 年龄 age的显示赋值,覆盖掉JVM默认赋值0 int age = 20; // 性别 sex的显示赋值,覆盖掉JVM默认赋值null String sex = "男"; // 定义出一个构造 public 对象创建成员赋值过程() { // sex的构造赋值覆盖掉了 显示赋值 sex = "nv"; } }
public class Test创建对象成员赋值过程 { public static void main(String[] args) { 对象创建成员赋值过程 demo = new 对象创建成员赋值过程(); System.out.println(demo.age);// 20 System.out.println(demo.name);// null System.out.println(demo.sex);// nv }
二、静态static
1 静态概念的引入
没有静态场景:
类型Student, 所有学生对象具有相同的属性值,就是schoolName = "第一中学", 发现问题 : 每一个对象都需要存储并且维护相同的属性值
1) 相同的属性,在每一个对象中都存储,浪费内存
2) 维护难度大,如果修改校名, 所有对象都需要修改校名
有静态场景 :
将所有对象相同属性,在类型中使用static静态关键字进行修饰, 使用静态修饰的成员存储在方法区中,可以被所有的对象所共有使用, 是静态所表现出的共享性
2.静态的特点
1.static : 关键字, 表示静态,静止的
2.静态属于类, 不属于任何对象;
3.静态优先于对象存在, 但是可以被对象共享使用
4.静态成员使用方式:
1) 类名.直接调用; (最推荐)
2) 使用 对象名.调用; (不推荐)
代码
public class StaticStudentTest { public static void main(String[] args) { Student s = new Student(); //The static field Student.schoolName should be accessed in a static way //System.out.println(s.schoolName);// 第一中学 System.out.println(Student.schoolName); // s.schoolName = "一中"; Student.schoolName = "一中"; Student s1 = new Student(); System.out.println(s1.schoolName);// 一中 }
3.静态使用的注意事项
- 静态方法中不能直接使用非静态(成员变量,非静态方法)
- 静态方法中,不能直接使用非静态成员变量
静态成员跟着类先进入内存, 非静态成员变量,跟着对象的创建后进入到堆内存中,先进入内存中的方法,无法直接使用后进入到内存中的成员
3.静态方法中, 不能直接调用非静态方法使用
静态成员跟着类先进入内存, 非静态方法需要在创建对象之后才能使用,先进入内存中的方法,无法直接使用后进入到内存中的非静态方法
4.静态方法中,不能使用this关键字
this表示本类对象的引用, 需要先创建出对象, this才能引用, 而静态优先于对象存在, 因此不能直接使用this关键字
代码
public class Demo01_静态中不能使用非静态 { // 1. 成员变量,定义一个非静态成员 int i = 10; public static void main(String[] args) { // 2. 静态方法中不能直接使用非静态成员变量 // System.out.println(i); // 3. 可以通过创建对象,调用非静态成员 Demo01_静态中不能使用非静态 demo = new Demo01_静态中不能使用非静态(); System.out.println(demo.i);// 10 // 4. 静态方法中不能直接调用非静态方法 // eat(); demo.eat(); // 5. 因为静态优先于对象存在, 所以静态方法中, 不能直接使用this关键字 // System.out.println(this.i);//Cannot use this in a static context } public void eat() { System.out.println("我在吃饭"); }
4.静态成员变量和非静态成员变量的区别
1.所属不同:
a : 静态成员变量 : 属于类
b : 非静态成员变量 : 属于对象
2.在内存中存储区域不同:
a : 静态成员变量 : 跟着类存储在方法区中
b : 非静态成员变量 : 跟着对象存储在堆内存中
3.生命周期不同:
a : 静态成员变量 : 跟着类进入方法区,存在了;当类从方法区消失(将类中的所有内容全部运行完毕), 静态成员消亡
b : 非静态成员变量 : 创建对象时, 存在了; 当对象再也没有任何使用的地方, 非静态成员变量跟着对象消亡
4.调用方法不同:
a : 静态成员变量: 1) 类名.直接调用 2) 对象名.调用
b : 非静态成员变量 : 对象名.调用
三、代码块
- 代码块 : 使用一对大括号包裹起来的一段代码, 将代码块放置到不同的位置, 具有不同的功能, 有不同运行机制
- 代码块的分类:
1) 局部代码块
2) 构造代码块
3) 静态代码块
4) 同步代码块(非常重要,多线程)
1.局部代码块
- 格式 : 代码使用一对大括号包裹起来
- 位置 : 方法中
- 作用 : 限定 定义在局部代码块中的变量作用范围, 如果变量无法再使用,这个变量所占有的内存空间就会被释放回收, 减少变量在内存中占有的时间, 节省内存
- 注意:
1) 局部代码块, 只限定 定义在局部代码块中的变量
2) 定义在局部代码块之外的变量, 局部代码块对其没有影响效果
举例 : 定义在局部代码块之外的变量i, 如果在局部代码块中修改值, 出了局部代码块之外,修改仍然生效
代码
public class Demo01_局部代码块 { public static void main(String[] args) { int i = 10; // 局部代码块: 限定定义在局部代码块中的变量使用范围 { i = 99;// 赋值,不受代码块影响 int y = 20; System.out.println(i + y);// 119 } // y cannot be resolved to a variable // System.out.println(y); 超出了y的使用范围 System.out.println(i);// 99 }
2.构造代码块
- 格式 : 代码使用一对大括号包裹起来
- 位置 : 类中方法外
- 作用 :
1) 可以通过构造代码块给成员变量进行赋值(默认赋值)
2) 如果多个构造方法都具有相同的处理逻辑,可以将相同的逻辑提升到构造代码块中实现和运行
4.运行机制:
每次创建对象时, JVM虚拟机主动调用构造代码块一次, 在构造方法执行之前调用
代码
public class Demo02_构造代码块 { int i; // 构造代码块 : 给成员赋值 { i = 10; System.out.println("构造代码块运行了"); System.out.println("构造执行~~~~~~~"); } public Demo02_构造代码块() { // System.out.println("构造执行~~~~~~~"); } public Demo02_构造代码块(int i) { this.i = i; // System.out.println("构造执行~~~~~~~"); } public static void main(String[] args) { Demo02_构造代码块 demo = new Demo02_构造代码块(); System.out.println(demo.i); Demo02_构造代码块 demo1 = new Demo02_构造代码块(99); }
3. 静态代码块(掌握)
- 格式 :
static {
代码;
}
2.位置 : 类中方法外
3.作用 :
1) 可以给静态成员变量进行赋值(默认值)
2) 如果有代码功能, 在类进入内存时,就需要马上执行,并且只执行一次,那么代码可以设计在静态代码块中
- 运行机制:
当类加载进入到方法区时(使用这个类时), JVM虚拟机主动调用一次静态代码块,与创建多少次对象,后续使用无关
- 代码块的运行顺序:
静态代码块--->构造代码块--->构造方法
public class Demo03_静态代码块 { static int j; { System.out.println("构造代码块"); } // 静态代码块 static { // 1. 给静态成员变量赋值 j = 99; System.out.println("静态代码块运行了"); } public Demo03_静态代码块() { System.out.println("构造方法~~~~~~"); } public static void main(String[] args) { /*System.out.println(Demo03_静态代码块.j);// 99 System.out.println(Demo03_静态代码块.j);// 99 */ Demo03_静态代码块 demo1 = new Demo03_静态代码块(); Demo03_静态代码块 demo2 = new Demo03_静态代码块(); }