目录
Question1:由类实例化对象,实例化的对象在哪存储呢?
Question3:实例化对象后,怎样通过对象的引用访问对象的成员变量?
Question5:普通成员变量和静态成员变量有什么区别呢?
Question5:普通成员方法和静态成员方法有什么区别呢?
Question6:在普通成员方法里面可以调用静态成员方法?
Question7:在静态成员方法里面可以调用普通成员方法?
Question1:get 和 set方法中的this是啥?
一、面向过程和面向对象
在了解类和对象之前,我们需要先了解面向过程和面向对象这两种编程思想。
面向过程:注重的是过程,将解决事情的过程分为很多步骤,每一步都得参与。
面向对象:注重的是对象,将一件事情拆成不同的对象,依靠对象的互相交互解决这件事。面向对象的过程就是:找对象、创建对象、使用对象
以做饭为例:
面向过程:洗菜-择菜-炒菜
面向对象:抽象为自己和妈妈两个实体,第一步:妈妈我饿了,第二步:妈妈去做饭,至于妈妈是如何做饭的,这个过程是不用考虑的。
二、类、类的实例化和对象
2.1 类和对象
类:类是一类对象的统称。
对象:是类具体化的一个实例。对象是由类实例化得到的,使用的关键字是new。
类相当于一个模板,通过类这个模板可以实例化无数个对象。
也可以把类认为是一个数据类型,类似于int这种,只不过这个数据类型是由我们自定义的。
class Person{
public String name; // 成员变量
public int age; // 成员变量
public void eat(){ // 成员方法
System.out.println("吃饭饭");
}
public void play(){ // 成员方法
System.out.println("玩儿");
}
}
public class TestDemo1 {
public static void main(String[] args) {
Person person1 = new Person(); // 实例化对象
person1.name = "zhangsan";
person1.age = 24;
person1.eat();
person1.play();
}
}
2.2 static关键字
在了解类的组成之前,我们先对static关键字做一个简单的了解。static英文原意是指“静态的”,但是在Java中的含义,和“静态的”这个字面意思没有任何关系。
static在Java中是表示“类的”,static 修饰的成员变量称为“类成员”,static修饰的成员方法是指“类方法”。由于类在程序中只有一份,static修饰的成员变量和成员方法在类里面,因此也就只有一份。
2.3 成员变量和成员方法
类里面有成员变量和成员方法。成员变量用来描述类的属性,成员方法用来描述类的行为。
根据是否有static修饰,成员变量被分为普通成员变量和静态成员变量,成员方法分为普通成员方法和静态成员方法两种。
(接下来我打算以提问的形式来分享一些细节的知识点)
Question1:由类实例化对象,实例化的对象在哪存储呢?
从图中可以看出:
同一个类可以实例化多个对象,如Person类就实例化person1和person2两个对象。
实例化后得到的对象存贮在堆上,person1和person2存储的是对象的地址。
Question2:可以在类中,对类的成员变量赋初值吗?
可以,但是一般不建议,因为类就是一个模板,没必要写死。如果你将String name = ”zhangsan“,实际上并不是所有的人都叫张三。
Question3:实例化对象后,怎样通过对象的引用访问对象的成员变量?
访问包含读和写。可以直接通过 . 来访问。具体使用见下面的代码。
可以通过 . 来访问对象的成员变量,并对成员变量赋初值。如果对象的成员变量没有被设置初始值,那么会被设置成一个默认的初值。
规则:
引用类型:默认值为null
各种数字类型:默认值为 0
boolean类型:默认值为false
Question4:引用=null,代表什么意思?
表示该引用不指向任何对象
Question5:普通成员变量和静态成员变量有什么区别呢?
普通成员变量 | 静态成员变量(有static修饰) | |
访问方式 | 需要先实例化一个对象,通过对象的引用才可以访问到 | 通过类名访问 |
存储位置 | 堆 | 方法区 |
通过一道题来帮大家加深一下理解。
从图中也可以看出,a作为 普通成员变量,是通过对象的引用来访问的,如t1.a++;count作为静态成员变量,是直接通过类名来访问的,如TestDemo.count++。
Question5:普通成员方法和静态成员方法有什么区别呢?
普通成员方法 | 静态成员方法(有static修饰) | |
访问方式 | 需要先实例化一个对象,通过对象的引用才可以调用 | 通过类名调用 |
注意:不能讨论方法的存储的位置。方法是不占内存的,调用方法时开辟栈帧就可。
Question6:在普通成员方法里面可以调用静态成员方法?
可以。因为调用静态成员方法依靠于类名,不依靠于对象。调用普通成员方法提供了一个对象,这个对象有没有都不会都不会产生影响。
Question7:在静态成员方法里面可以调用普通成员方法?
不可以。静态方法直接通过类名调用,没有对象,调用普通成员方法需要一个对象,所以没办法调用。
2.4 总结
普通成员变量通过对象调用,存储在堆上。
静态成员变量通过类名调用,存储在方法区上。
普通成员方法的调用依赖于对象,在其内部可以调用静态成员方法。
静态成员方法的调用依赖于类名,在其内部不能调用普通成员方法。
三、封装
3.1 为什么需要封装
在写代码时会涉及到两种角色,一种是类的实现者,一种是类的调用者。为了避免类的实现者改了类的成员变量后,类的调用者写的代码中也需要跟着改。因此,将类的成员变量使用private修饰,类的调用者就获取不到该成员变量,依据提供的public的访问方法来访问成员变量。(一般情况下,这个public的访问方法是不会修改的)
封装的本质是:让类的调用者不必过多了解类的实现者是如何实现类的,只需要知道是如何使用类就行了。这样就可以降低类使用者的学习和使用成本,从而降低了复杂程度。
3.2 如何封装以及封装后如何访问
使用private实现封装,封装后提供一个public的访问方法。可以再IDEA里面生成getter和setter方法,提高开发效率(右键--generate--getter and setter)。
class Person{
private String name;
private int 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 Main1{
public static void main(String[] args) {
Person person1 = new Person();
person1.setAge(24);
person1.setName("zhangsan");
person1.getName();
person1.getAge();
}
}
Question1:get 和 set方法中的this是啥?
如果没有this:
this是指当前对象的引用,加上this.name 就是指当前引用指向的对象的name,而不是形参name。
3.4 总结
使用private进行封装,提供一个public的访问方法。IDEA可以自动生成getter和setter方法。this是指当前对象的引用。
四、构造方法
4.1 new的执行过程
第一步:为对象分配内存空间
第二步:调用合适的构造方法。
4.2 构造方法
构造方法是一种特殊方法,构造函数的方法名和类名一样,没有返回值。使用关键字new实例化对象时会被自动调用,用于完成初始化操作。
4.3 构造方法的特点
①方法名和类名一样,没有返回值。
②构造方法有多个。
③在没有定义任何的构造函数前,编译器会自动生成一个不带参数的构造方法。
④不同的构造函数之间构成了重载。重载的特点:方法名相同,参数列表不同,返回值不做要求。
4.4 解密this(重点)
this是指当前对象的引用。
因为this依赖于对象,static不依赖对象,直接通过类调用,所以,this在static方法里面不能使用。
this有三种用法:
this.成员变量
this.成员方法
this(参数):this调用其他的构造函数,必须放在第一行。
class Person{
private String name;
private int 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 Person(String name) {
this("zhangsan",11); // this调用下面的构造函数,必须写在第一行
this.name = name;
//this("zhangsan",11); //如果没写在第一行,编译不通过
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main1{
public static void main(String[] args) {
Person person2 = new Person("zhangsan"); // 可以根据需要选择合适的构造函数
Person person3 = new Person("lisi",24);
}
}
4.5 总结
构造函数不止一个,在new对象时选择合适的构造函数完成对象的初始化操作。
编译器会提供一个不带参数的构造函数的前提是------当前类中没有提供任何的构造方法。
this可以调用其他的构造函数,但是必须得写在第一行。
五、代码块
这些都是定义在方法外面,类里面。
5.1 普通代码块(用法较少)
定义在方法中的代码块。
public static void main(String[] args) {
{
int a = 10;
System.out.println(a); //10
}
int a = 100;
System.out.println(a); // 100
}
5.2 构造代码块(实例代码块)
定义在类中的代码块,一般用于初始化成员变量。
class Person{
private String name;
private int 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 Person(){
System.out.println("我是构造函数哦");
}
{
this.name = "zhangsan";
this.age = 20;
System.out.println("我是实例代码块哦");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Main1{
public static void main(String[] args) {
Person person1 = new Person();
System.out.println(person1.toString());
}
}
运行结果:
注意:实例代码块优于构造函数执行。
5.3 静态代码块
初始化静态的数据成员和需要提前准备的数据。
class Person{
private String name;
private int age;
private static String sex;
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 Person(){
System.out.println("我是构造函数哦");
}
{
this.name = "zhangsan";
this.age = 20;
System.out.println("我是实例代码块哦");
}
static {
sex = "female";
System.out.println("我是静态代码块哦");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Main1{
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
System.out.println(person1.toString());
}
}
运行结果:
总结:在运行时,静态代码块先执行,但对于同一个类中,静态代码块只执行一次。
class Person{
private String name;
private int age;
private static String sex;
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 Person(){
System.out.println("我是构造函数哦");
}
static {
sex = "female";
System.out.println("我是静态代码块1哦");
}
static {
sex = "female";
System.out.println("我是静态代码块2哦");
}
}
public class Main1{
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
}
}
运行结果:
总结:如果都是静态的或者实例的,执行的顺序和定义的顺序有关,谁在前先执行谁。
里面不能用this哦!!!
5.4 总结
运行顺序:
先执行静态代码块 再执行实例代码块 最后再执行方法。这里的执行顺序和写的顺序无关。
六、匿名对象
没有引用的对象称为匿名对象。匿名对象只能在创建对象时使用。
使用范围:如果一个对象只是使用一次,后面不需要用了,可以考虑使用匿名对象。
class Person{
private String name;
private int 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 Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Main1{
public static void main(String[] args) {
System.out.println(new Person("zhangsan", 12).toString());
}
}
七、toString方法
toString 方法会在 println 的时候被自动调用。
将对象转成字符串这样的操作我们称为 序列化.
toString 是 Object 类提供的方法, 我们自己创建的 Person 类默认继承自 Object 类, 可以重写 toString 方法实现我们自己版本的转换字符串方法.
@Override 在 Java 中称为 "注解"
总结
1.类中有普通成员变量、静态成员变量、普通成员方法和静态成员方法。
2.普通成员变量和普通成员方法通过对象访问;静态成员变量和静态成员方法通过类名访问。
3.静态成员方法内部不能调用普通成员方法;普通成员方法内部可以调用静态成员方法。
4.Person person1 = new Person(),person1中存的是对象的引用,在栈上,实例化后的对象在堆上存储。person1中存储的是对象在堆上的地址。静态成员变量存储在方法区。
5.使用new实例化对象,使用private封装。
6.实例化一个对象分为两步,给对象分配内存空间,调用合适的构造方法。
7.构造方法有多个,如果在类中未定义任何构造方法,编译器会默认提供一个不带参数的构造方法。多个构造方法之间构成重载。
8.重载:方法名相同,参数列表不同,返回值不做要求。
9.this 是指当前对象的引用
10.执行顺序:静态代码块 优于 实例代码块 优于 普通方法(与定义的顺序无关)
11.对于同一个类来说,静态代码块只执行一次。
12.多个静态代码块/实例代码块,谁在前先执行谁。