构造器
也叫构造方法 ---constructor,本质上是一个方法,但是有特殊性
特点
-
方法名和类名一致, 唯一允许首字母大写的方法名
-
没有返回值声明, 甚至连void也不允许
-
不能被关键字 : static, final, synchronize, native, abstract等修饰
-
不能像普通方法一样随意调用, 只能调用一次. 某个对象的生命周期中只能调用一次.
总结
- **Java****语言中,每个类都至少有一个构造器
- 默认构造器的修饰符与所属类的修饰符一致**
- 一旦显式定义了构造器,则系统不再提供默认构造器
- 类可以创建多个重载的构造器
- 父类的构造器不可被子类继承
- 构造器重载, 还可以连环调用, 但是一定要保证有一个构造器中是没有this(…). 防止无限递归.
this()
-
特殊调用必须是构造器中的第一行. 对其他构造器的调用必须要先于此构造器的特有代码, 最终要体现在继承中子类对象的初始化要晚一些.
-
在java中,this关键字比较难理解,它的作用和其词义很接近。
-
它在方法内部使用,即这个方法所属对象的引用;谁调用this就是谁.
-
它在构造器内部使用,表示该构造器正在初始化的对象。
注意
-
**使用this()必须放在构造器的首行!
-
使用this调用本类中其他的构造器,保证至少有一个构造器是不用this的。
-
class TeacherV0 { // 成员变量(member), 成员可以使用修饰符修饰, 注意 : 局部变量无法使用访问控制修饰符 // private表示私有的意思, 一旦私有, 外部无法访问, 只能在类内部访问 // 这样的处理称为 "封装", 成员私有化. private String name = "某老师"; // 属性如果没有显式赋值, 它的值就是默认值0 private int age; // 缺省值是0 private String gender = "未知"; // 构造器重载, 还可以连环调用, 但是一定要保证有一个构造器中是没有this(). 防止无限递归. // this(...) 特殊调用必须是构造器中的第一行. 对其他构造器的调用必须要先于此构造器的特有代码 public TeacherV0() { // 无参, 调用简单, 功能单一, 有其特殊性, 创建对象简单, 无参构造器将来要为子类专供. /* this.name = "佟刚"; this.age = 40; this.gender = "男"; */ this("佟刚", 40); // 对其他构造器的调用 System.out.println("Teacher()..."); // 此构造器的特有代码 } public TeacherV0(String name, int age) { /* this.name = name; this.age = age; this.gender = "男"; */ this(name, age, "男"); // 重载的构造器的调用, 必须使用this(); System.out.println("Teacher(String, int)..."); } public TeacherV0(String name, int age, String gender) { // 全参, 功能强大, 调用复杂 //this(); this.name = name; //this.age = age; setAge(age); // 统一的参数合法性判断. this.gender = gender; System.out.println("Teacher(Stintg, int, String)..."); } /* 这种方法也是允许存在的, 但是不要这样写, 容易引起误会.*/ public void TeacherV0(String name) { System.out.println("我是普通方法, 不是构造方法, 我是捣乱的, 忽略我"); } // set方法有参无返回 public void setName(String name) { // 间接设置属性的方法,称为set方法 //name = name; // 变量访问的就近原则, 会导致左面的name不是属性, 而是局部变量. this.name = name; // this表示当前对象. 当局部变量参数和成员变量冲突时, 成员变量必须加上限定 } // get方法无参有返回 public String getName() { // 间接获取name属性值的方法, 称为get方法 return this.name; } // 使用方法间接给属性赋值的好处是 可以加上 逻辑判断, 使得数据得到保护... public void setAge(int age) { if (age < 0 || age > 150) { // 如果数据非法, 直接弹栈 System.out.println("参数年龄太大"); return; // 提前弹栈, 会导致this.age没有刷新值. 保持了原有的0 } this.age = age; } public int getAge() { return this.age; } public void setGender(String gender) { this.gender = gender; } public String getGender() { return this.gender; } // 成员方法(member) public void lesson() { System.out.println(this.say() + "老师在上课"); // 成员互访 } public void eat(String some) { System.out.println(name + "老师在吃" + some); } // 返回对象的详细信息字符串, 所有属性值的拼接 public String say() { return "姓名 : " + name + ", 年龄 : " + age + ", 性别 : " + gender; } }
-
每日一考_day08
- 什么是封装? 如何封装?
成员私有化, 防止外部直接访问. 成员包括属性, 方法, 构造器, 内部类.
使用private修饰成员, 就可以封装.
-
什么是构造器,作用是什么? 有什么特点(4点)
也称为构造方法, 在对象的创建过程中会由JVM调用它, 作用是对对象进行初始化工作
- 方法名必须和类名一致, 唯一允许使用首字母大写的方法.
- 不声明返回值类型, 甚至连void也没有.
- 不能被关键字:abstract, static ,final, synchronized, native等 修饰
- 不能像普通方法一样随意调用, 只能在对象创建时调用仅有的一次.
-
创建一个对象的步骤(7步)
- 在方法区要检查要创建的对象所属的类模板信息是否存在(类是否已经加载)
- 如果不存在, 必须由类加载器加载类模板, 加载到方法区中, 永久保存它.
- 如果存在, 则不加载, 保证类模板在方法区中只有一份.
- 依据类模板中的所有属性定义信息, 在GC区中开辟空间. 获取到对象的地址.
- 把此空间全部写0. 底层操作 : memset(内存地址, 0, 长度); 效果是所有属性拥有0
- 检查属性是否有显式赋值, 如果有, 则执行显式赋值.
- 执行构造方法, 进一步对属性进行赋值等初始化工作.
- 把对象地址返回给创建者
-
this关键字表示什么含义?
this表示的是对象, 当前对象
- 如果是在构造器中, this表示正在创建中的对象, this.成员.
- 如果是在构造器中, this(…) 表示对其他重载的构造器的调用.
要求 :
-
this(…) 必须在构造器的首行,
-
一定要保证至少有一个构造器中没有this(…);
-
- 如果是在方法中或属性的使用中, 表示的是正在访问这个属性或方法的对象的引用
Xxx ref1 = new Xxx(); ref1.method(); // 对象方法的调用必须要有对象. Xxx ref2 = new Xxx(); ref2.method(); ref1.field = “值”; class Xxx { String field = this.xxx(); public void method() { // ref1.method() 调用中, this 代表就是ref1 // ref2.method() 调用中, this 代表就是ref2 } }
this 就是指调用者对象
对象 包括属性, 或者说是拥有属性
对象地址 : 对象在GC区中的第一个字节的编号. 也称为首地址
对象关联
对象关联 : 一个对象完全拥有另外一个类的对象.
关联目的 : 随时随时地方便地使用另一个对象.
如何关联 : 在前者的类中把另外一个类的对象作为属性即可. 属性是成员, 成员意味着它们之间可以直接互访
一旦把对象作为我的属性, 需要处理全参构造器, 因为是属性也要提供get/set方法, 改造say()方法
public class Teacher {
private String name;
private int age;
private String gender;
private Computer myComputer; // 对象关联
public Teacher() {}
public Teacher(String name, int age, String gender, Computer myComputer) {
this.name = name;
this.age = age;
this.gender = gender;
this.myComputer = myComputer;
}
public void setMyComputer(Computer myComputer) {
this.myComputer = myComputer;
}
public Computer getMyComputer() {
return myComputer;
}
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 setGender(String gender) {
this.gender = gender;
}
public String getGender() {
return gender;
}
public String say() {
return "姓名 : " + name + ", 年龄 : " + age + ", 性别 : " + gender + ", 我的电脑 : " + myComputer.say();
}
//public void lesson(Computer computer) {
public void lesson() {
System.out.println(name + "老师在使用电脑[" + myComputer.say() + "]上课");
}
public void film() {
System.out.println("使用电脑[" + myComputer.say() + "]看电影");
}
}
package
- 包 : 用于管理功能类似的多个类.
package 包名.子包名.子子包名.子子子包名; // 这个语句总是在源文件中第一行
- 作用 : 告诉编译器, 当前源文件中的类, 编译后的.class文件放入指定的包目录中.
通常情况下包有4层
package 机构类型.机构名称.项目名称.模块名称; // 包名全部小写
package com.atguigu.javase.javabean;
-
一旦使用了package, 会带来两个麻烦
1. 编译时必须加上选项-d : javac -d 目标目录路径 源文件名
-d表示目标目录
常见写法 : javac 空格 -d 空格 . 空格 源文件名
2. 使用时, 如果是跨包使用本类, 在别的包的类中必须使用全限定名称来使用本类,
全限定名称就是 所有包名.类名 : 包名.子包名.子子包名.子子子名包.类名;
比如在测试类中, 要想使用本类. com.atguigu.javase.javabean.Teacher
练习 : 把Person类和Phone类都打包在com.atguigu.javase.javabean包中
把PersonTest类打包在com.atguigu.javase.test包中
在测试类中, 使用全限定类名来使用Person类和Phone类, 编译所有程序, 运行测试.
数组
-
数组 : 一组相同任意类型的数据的组合, 便于统一管理.
-
数组 : 由多个元素组成, 每个元素相当于是数组对象的属性
-
数组属于引用类型, 数组的数据则是对象.
-
数组声明 :
元素数据类型[] 数组名;
- 数组创建 :
数组名 = new 元素数据类型[元素个数];
public class ArrayTest {
public static void main(String[] args) {
// 声明 : 元素数据类型[] 数组名;
int[] arr; // 此时没有数组对象存在的.
// 创建 : new 元素数据类型[元素个数];
arr = new int[5]; // 在GC区中创建一个元素有5个的int型数组. 数组对象创建好以后, 所有元素都有缺省值0
// 数组元素的定位(访问), 通过首地址(数组名)[偏移量(也称为下标, 索引, 脚标)]
// 每个元素都是一个小变量.
arr[2] = 4;
arr[0] = 3;
arr[arr[0]] = 1;
arr[arr[2]] = 5;
// 分析每个元素的值
System.out.println(arr[0]); // 3
System.out.println(arr[1]); // 0
System.out.println(arr[2]); // 4
System.out.println(arr[3]); // 1
System.out.println(arr[4]); // 5
}
}
每日一考_day09
-
类模版信息保存在内存中的什么位置,里面包含了哪些信息,类模版信息的特点和作用是什么?
在堆内存的永久区(方法区)
类模版中包含的信息有:
- 属性的定义信息(修饰符,数据类型,属性名,显示值)
- 所有方法的代码。(不是在运行中的状态),如果要运行,必须把它压入栈中执行。
- 构造器,类名、父类、接口、注解。。。
-
数组是什么? 什么类型的数据可以创建数组?
一组相同任意类型的数据的组合,便于统一管理
任意数据类型,包括基本型和引用型
-
如何声明并创建数组?有几种方式?
声明: 数据类型[] 数组名;
创建: new 元素数据类型[长度];
声明和创建 : 元素数据类型[] 数组名 = new 元素数据类型[长度];
静态方式1 :适用于数据量小,元素值确定的情况
元素数据类型[] 数据名 = new 元素数据类型[]{值1,值2......};
静态方式2 : 使用受限:声明和初始化必须在同一条语句上才可以这样
元素数据类型[] 数组名 = {元素值1 ,值2 .....};
-
判断
- 数组的长度可以随意变化 F
- 数组的元素类型和数组类型是一回事 F
- 数组的访问是通过数组名.下标实现的 F
- 数组的访问方式是数组名(首地址)+ 偏移量算出来的 T
- 数组的元素类型可以随意变化 F
Student[] stuArr = new Student[3]; // 1
stuArr[0] = new Student(20,"小明","男");
stuArr[1] = new Student(30,"小丽","女");
for (int i = 0;i < stuArr.length;i++){
System.out.println(stuArr[i].say());
}
在1位置处有几个对象被创建,什么对象? 1,String[]
以上的代码有没有问题?如何改进? 有问题
- 将stuArr[2]赋上值(Student对象)
- 加判断语句,若为null不say()即可