面向对象
对象在内存中的存在形式
对象也是一个引用数据类型.
对象创建的流程分析
class Person{
int age = 90;
String name;
public Person(String n,int a){
name = n;
age = a;
}
}
//main中
Person p = new Person("jack",20);
- 在方法区中加载Person类信息(Person.class), 只会加载一次
- 在堆中分配空间(地址)
- 完成对象的初始化[3.1 默认初始化 age = 0 name = null 3.2 显式初始化 age = 90 name = null 3.3 构造器的初始化 age = 20 name = jack(字符串,堆中的对象的name地址指向在常量池中jack)]
- 对象在堆中的地址, 返回给p(p是对象名, 也可以理解成是对象的引用)
对象分配机制
Person p1 = new Person();
a1.age = 10;
a1.name = "小明";
Person p2 = p1;//把p1赋给了p2 , 让p2指向p1
System.out.println(p2.age);
//p2,age是什么?
匿名对象
public class Test{ //公有类
int count = 9; //属性
public void count1(){ //Test类的成员方法
count = 10; //这个count就是属性 改成10
System.out.println("count1=" + count); //10
}
public void count2(){ //Test类的成员方法
System.out.println("count2=" + count++);
}
//这是Test类的main方法, 任何一个类,都可以有main
public static void main(String args[]){
//1. new Test() 是匿名对象, 匿名对象使用后, 就不能再使用(一次性)
//2. new Test().count1() 创建好匿名对象后, 就调用count1()
new Test().count1();
Test t1 = new Test();
t1.count2();
t1.count2();
}
}
Java内存的结构分析:
- 栈: 一般存放基本数据类型(局部类型)
- 堆: 存放对象
- 方法区: 常量池(常量, 比如字符串), 类加载信息
属性(成员变量\字段)细节
- 属性的定义语法变量, 示例 : 访问修饰符 属性类型 属性名;
- 属性的定义类型可以为任意类型, 可以是基本类型或引用类型.
- 属性如果不赋值, 有默认值. 和数组一样. String null / int 0 / short 0 / byte 0 / long 0 / float 0.0 double 0.0 / char \u0000 / boolean false
方法调用机制
当返回后, getSum
栈就被释放(销毁)了
小结
- 当程序执行到方法时, 就会开辟一个独立的空间(栈空间)
- 当方法执行完毕, 或者执行到return语句时, 就会返回
- 返回到调用方法的地方
- 返回后, 继续执行方法后面的代码
- 当main方法(栈)执行完毕, 整个程序退出
- 基本数据类型, 传递的是值(值拷贝), 形参的任何改变不影响实参(方法传参机制)
- 引用数据类型, 传递的是地址(传递也是值, 但是值是地址), 形参的改变会影响到实参(方法传参机制)
方法使用细节
一个方法最多有一个返回值, [ 如果要返回多个结果 , 返回数组 ]
public int[] getSum(int n1,int n2){ //创建一个数组 int[] resArr = new int[2]; resArr[0] = n1 + n2; resArr[1] = n1 - n2; return resArr; }
返回类型可以是任意类型, 包括基本类型或引用类型
如果方法要求有返回数据类型, 则方法体中最后的执行语句必须为 return 值, 而且要求返回值类型必须和 return 值类型一致或兼容(自动转换)
public double f1(){ //错误,缺少返回语句 }
如果方法是void, 则方法体中可以没有return语句, 或者 只写return(不能有返回值)
同一个类中的方法, 直接调用
跨类中方法A类调用B类方法, 需要通过对象名调用
class A{ public void m1(){ System.out.println("A类中的 m1()被调用"); B b = new B(); //创建对象 b.hi(); System.out.println("A类中的 m1()继续执行"); } } class B{ public void hi(){ System.out.println("B类中的 hi()被调用"); } }
形参列表的细节
- 一个方法可以有0个参数, 也可以有多个参数, 中间用逗号隔开
- 参数类型可以是任意类型, 包括基本类型或引用类型
- 调用带参数的方法时, 一定对应着参数列表相同类型或者兼容类型(低精度向高精度) 的参数
- 方法定义时的参数称为形式参数, 方法调用时的传入参数称为实际参数
- 实参和形参的类型要一致或者兼容, 个数, 顺序必须一致
方法重载
java允许方法名相同, 但是要求形参列表不同
返回类型没有要求
可变参数
java允许将同一个类中多个同名同功能但参数个数不同的方法, 封装成一个方法, 通过可变参数实现
class HspMethod{
//计算2个数的和, 3个数的和, 4.....
//可以使用方法的重载(但是繁琐)
//使用可变参数封装成方法
//1. int...表示接收的是可变参数, 类型是int, 即可以接收多个int(0 - 多)
//2. 使用可变参数时, 可以当作数组来使用 即nums可以当作数组
public int sum(int...nums){
System.out.println("接收的参数的个数:" + nums.length);
//遍历求和
int res = 0;
for(int i = 0; i < nums.length; i++){
res += nums[i];
}
return res;
}
}
可变参数的细节
可变参数的实参可以是数组
//main int[] arr = {1,2,3}; T t1 = new T(); ti.f1(arr); class T{ public void f1(int...nums){ System.out.println("长度=" + nums.length); } }
可变参数的本质是数组
可变参数可以和普通类型的参数一起放在形参列表, 但必须保证可变参数放在最后
一个形参列表只能出现一个可变参数
变量作用域
局部变量与全局变量(属性变量)
全局变量可以不赋值, 直接使用, 因为有默认值, 局部变量必须赋值后才能使用, 因为没有默认值
作用域细节
属性和局部变量可以重名, 访问时遵循就近原则
class Person{ String name = "jack"; public void say(){ //就近原则 String name = "king"; System.out.println(name); } } //输出的是king
属性生命周期较长, 伴随着对象的创建而创建,伴随着对象的销毁而销毁. 局部变量,生命周期较短, 伴随着它的代码块的执行而创建, 伴随着代码块的结束而销毁. 即在一次方法调用过程中.
作用域范围不一样
全局变量 : 被本类使用或者其他类使用(需要通过对象的调用)
局部变量 : 只能被本类中对应的方法中使用
修饰符的不同
全局变量 : 可以加修饰符
局部变量 : 不能加修饰符
构造器
[修饰符] 方法名(和类名保持一致) (形参列表){
方法体;
}
//构造器没有返回值
//主要作用是初始化
构造器细节
一个类可以定义多个构造器, 即构造器的重载
如果程序员没有定义构造器, 系统会自动给类生成一个默认无参构造器(也叫默认构造器), 比如
Dog(){}
一旦定义了自己的构造器, 默认的构造器就覆盖了, 就不能再使用默认的无参构造器, 除非显式的定义一下, 即
Dog(){}
Dog dog1 = new Dog();//使用的是默认的无参构造器
this关键字
class Dog{
String name;
int age;
public Dog(String name,int age){
//this.name 就是当前对象的属性name
this.name = name;
//this.age 就是当前对象的属性age
this.age =age;
}
}
深入理解this
虚拟机会给每个对象分配this, 代表当前对象
哪个对象调用, this就代表哪个对象
this细节
this关键字可以用来访问本类的属性, 方法, 构造器
public void f3(){ //传统方式(按照的是就近原则访问属性,但是如果在方法中有局部变量,那么这个name就是局部变量,不是属性) System.out.println("name=" + name + "num=" + num); //也可以使用this访问属性(准确定位到属性) System.out.println("name=" + this.name + "num=" + this.num); }
this用于区分当前类的属性和局部变量
访问成员方法的语法 : this.方法名(参数列表)
访问构造器语法 : this(参数列表) 只能在构造器中使用(即只能在构造器中访问本类另外一个构造器) 如果有访问构造器语法 : this(参数列表); 必须放在第一条语句
class T{ public T(){ //这里去访问 T(String name, int age) 构造器 this("jack",100); System.out.println("T() 构造器"); } public T(String name, int age){ System.out.println("T(String name, int age) 构造器"); } }
this不能在类定义的外部使用, 只能在类定义的方法中使用