面向对象:
1.1内存图
一个对象的内存图:
a.MyTest.class类加载到方法区,调用主方法main() 入栈;
b.在栈中运行main方法,当jvm看到Student时,会自动把Student类加载到方法区;当看到局部变量s时,会在栈中开辟一块空间;当看到new Student()时,会在堆内存中开辟空间,并将堆内存中的对应地址0x001赋值给s;还会拿到方法区的地址值指向方法区;
c.在main方法中运行到s.name这一步时,s根据对象给他的地址值,去堆内存中找到相应的对象,再给堆内存中的变量赋值;
d.在main方法中运行到s.eat()这一步时,并不是s在调用eat()方法,而是s根据对象给他的地址值,去堆内存中找到相应的对象,再用对象去方法区中找到eat()方法,然后将eat()方法压到栈中(入栈),根据地址值给堆内存中的变量赋值,调用完毕eat()方法会出栈;
e.main方法运行结束后会出栈。
两个对象的内存图:
三个对象的内存图:
1.2成员变量和局部变量的区别
局部变量 | 成员变量 |
---|---|
定义在方法中的变量或者方法声明上的变量(形参) | 定义在类中 方法外的变量 |
它属于方法 | 它属于对象,也叫做实例变量 |
随着方法的调用而产生,随着方法的调用完毕而消失 | 随着对象的创建而产生,随着对象的回收而消失 |
必须赋值才能使用 | 有默认值 |
存在栈内存 | 存在堆内存 |
当成员变量和局部变量重名时,变量的访问原则遵循就近原则:方法内调用变量时,如果在方法内部这个局部的范围中找到了要使用的变量,就会使用;没找到就去成员范围找,再没找到就会报错了。
package org.westos.demo3;
public class Teacher {
String name="沈某某";
int age;
public void show(int age){
String name="张三";
age=100;
System.out.println(name);
System.out.println(age);
}
}
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.show(20);
// 由于就近原则,结果为 张三 100
}
新语法:可以将多个类,并列的定义到一个.java文件中,public 只能加给其中作为入口的那个类,但是建议一个类就是一个.java 文件
public class MyTest {
public static void main(String[] args) {
int num = 10;
// 当你以后看到一个方法的形参,要一个 类 类型,你就传递一个该类的对象
// 基本类型作为参数传递,属于值传递:形参的改变,不影响实参
// 引用类型作为参数传递,属于引用传递,传递的是地址值,形参的会影响实参
Student student = new Student();
System.out.println("new 的对象"+ student);// 地址值:1540e19d
test(student, num);
System.out.println(num); //10
System.out.println(student.num);//30
}
public static void test(Student s, int num) {
System.out.println("方法形参收的那个对象"+s);
// 地址值:1540e19d,引用传递,传递的是地址值,形参的会影响实参
num += 20;
s.num = num;
}
}
class Student {
int num = 120;
}
1.3匿名对象
1.什么是匿名对象:没有名字的对象,可以直接打点调属性 调功能,
2.匿名对象应用场景:a.当你只想要调用一次的时候,就可以使用匿名对象来调用;b.匿名对象可以作为参数来传递:当一个方法的形参要一个 类 类型,就传一个该类的对象
public class MyTest {
public static void main(String[] args) {
int num = new Dog().num; // 打点调属性
System.out.println(num); // 100
System.out.println("=====================");
// 打点调功能,同一个对象,调用了eat()方法两次
Dog dog = new Dog();
dog.eat(); // 狗吃骨头
dog.eat(); // 狗吃骨头
System.out.println("========================");
// 两个匿名对象,各调用了一次
new Dog().eat(); // 狗吃骨头
new Dog().eat(); // 狗吃骨头
System.out.println("=============================");
// 当你以后看到一个方法的形参,要一个 类 类型,你就传一个该类对象。
Dog dog1 = new Dog();
test(dog1, 20);
// 匿名对象,作为参数传递
test(new Dog(), 120);
System.out.println(dog1.num); //20
System.out.println(new Dog().num); // 100
}
public static void test(Dog dog, int num) {
dog.num = num;
//System.out.println(dog.num);
}
}
class Dog {
int num = 100;
public void eat() {
System.out.println("狗吃骨头");
}
}
DOG:流程
a.MyTest.class–main()
main()进栈执行
b.Dog dog1=new Dog();
在堆开辟空间0x001,然后对成员变量 初始化
num=100;
c.test()方法进栈执行,
test(0x001,num=20);
弹栈走人 但是改了值
d.test(new Dog(),120);
开辟新空间0x002,被100覆盖
dog.num=num=120,100被120覆盖
e.new Dog().num.sout;
开辟新空间0x003 赋值 被100覆盖
1.4 私有化成员变量–权限修饰符
对象名.成员变量=值 给成员变量设置值的方式,不能排除一些不合理的数据。
private(私有的)权限修饰符,可以修饰成员变量,也可以修饰成员方法,被修饰的成员,只能在本类中访问,外界无法直接访问。
我们可以提供公共的设置和获取方法,让外界通过调用方法来给成员变量设置值和获取值。
封装好处:隐藏实现细节,提供公共的访问方式;提高了代码的复用性;提高安全性。
package org.westos.demo;
public class Student {
// 以后我们在定义一个类时,会把成员变量私有掉,然后提供公共的set get 方法,让外界通过set get方法间接的去给成员变量设置值,以及获取成员变量的的值
private String name;
// private修饰成员变量和修饰成员方法
private int age;
// 设置和获取的方法
public void setAge(int nl){
if(nl>=0&&nl<=100){
age = nl;
}
}
public void setName(String mz){
name=mz;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public void show() {
System.out.println("姓名:" + name + "===年龄:" + age);
}
}
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
//student.name="张三";
//我们采用 对象名.成员变量名=值 这种方式给成员变量设置值的方式,他不能排除一些不合理的数据。
//我们可以采用一种手段,来屏蔽掉 对象名.成员变量名=值 这种设置值的方式。
//student.age=200;
//System.out.println(student.name);
//System.out.println(student.age);
student.setName("张三");
student.setAge(100);
String name = student.getName();
int age = student.getAge();
System.out.println(name); // 张三
System.out.println(age); // 100
student.show();
}
}
public–公共的 权限修饰符 可以修饰类 成员变量和成员方法,范围最大,在任何地方(同一个包 不同的包下都可以)都能访问到。
四个权限修饰符:public > protected > 不写(默认)缺省的 > private,都可以修饰成员变量和成员方法,修饰类只能用public或者缺省的。范围由大到小,常用的就是public和private。
1.5 this关键字的概述和应用
为什么要有this:当调用set方法时,形参的名称和成员变量的名称重名了,发现成员变量被致盲了,我们想要区分出来成员变量和局部变量,我们可以使用一个关键字this来区分。
this关键字特点:简单的记,this代表该类的一个引用,就是该类的对象,哪个对象调用这个方法,方法中的this就代表那个对象。方法中的this 代表那个调用者
this的应用场景:解决局部变量隐藏成员变量。
package org.westos.KeTang;
public class ThisTest {
private String type;
private double storage;
private int Android;
public void setType(String type) {
this.type = type;
// 调用set方法时,形参的名称和成员变量的名称重名
}
public void setStorage(double storage) {
if (storage <= 1024.0) {
this.storage = storage;
}
}
public void setAndroid(int Android) {
if (Android <= 13) {
this.Android = Android;
}
}
public String getType() {
return type;
}
public double getStorage() {
return storage;
}
public int getAndroid() {
return Android;
}
// 定义相关功能
public void show() {
System.out.println("机型:" + type + " 内存:" + storage + "G Android版本:" + Android);
}
}
小技巧:快速生成get和set
private String name;
private int age;
Alt+Insert弹出菜单 选择Getter and Setter
package org.westos.KeTang;
public class ThisUse {
public static void main(String[] args) {
ThisTest mi = new ThisTest();
mi.setType("MI9");
mi.setStorage(130.0);
mi.setAndroid(11);
String type=mi.getType();
double storage=mi.getStorage();
int Android=mi.getAndroid();
System.out.println(type); // MI9
System.out.println(storage); // 130.0
System.out.println(Android); // 11
mi.show(); // 机型:MI9 内存:130.0G Android版本:11
System.out.println("------------------");
ThisTest HuaWei = new ThisTest();
HuaWei.setType("Mate20");
HuaWei.setStorage(128.0);
HuaWei.setAndroid(10);
HuaWei.show();// 机型:Mate20 内存:128.0G Android版本:10
}
}
1.6 构造方法
a.构造方法概述和作用:创建对象,给对象中的成员进行初始化(创建一个类的对象 使用关键字new来调用构造方法完成对类的实例化)
b.语法:方法名和类名相同;没有返回值,连void也没有 - - - public Student(){}
当你定义一个类之后,这个类中,默认就存在有空参的构造方法。
多个参数的构造方法 public Student(写入多个参数){}
c.可以借助有参构造创建对象,顺便给对象的成员变量设置值,比较方便;
d.一旦我们手动给出了有参构造,那么默认无参构造就没有了,如果还想借助空参构造方法,就必须自己给出。建议永远自己给出无参构造方法。
package org.westos.demo3;
public class Dog {
private String name;
private int age;
private int sex;
// 按alt+insert键 弹框一个框,选择constructor选项,来生成空参/有参构造,以及get set 方法。
public Dog() {
System.out.println("空参调用了");
}
// 有参构造
public Dog(String name, int age) {
System.out.println("有参构造调了");
this.name = name;
this.age = age;
}
// get set方法
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;
}
private void show(){
//adfasdfasdfasdfasfdasdf
}
public void show2() {
show();
}
}
以后定义一个类,私有化成员变量 ,提供get set 方法,提供空参构造和有参构造。
小技巧:快速生成构造方法:
Alt+Insert弹出菜单 选择constructor 来生成空参 有参 以及get set方法
public class MyTest {
public static void main(String[] args) {
//借助空参构造创建对象。
Dog dog = new Dog();// 空参调用了
dog.setName("小白");
dog.setAge(20);
System.out.println(dog.getName());// 小白
System.out.println(dog.getAge());// 20
System.out.println("=============================");
Dog dog1=new Dog("旺财",3);// 有参构造调了
System.out.println(dog1.getName());// 旺财
System.out.println(dog1.getAge());// 3
}
}