面向对象编程的本质是:以类的方式组织代码,以对象的方式组织数据。
面向对象的三大特性:封装、继承、多态。
class Person {
int age = 1;
String name;
Person (String name , int age) {
this.name = name;
this.age = age;
}
}
//利用new 关键字进行类对象的创建
Person person = new Person("小倩",20);
当使用new关键字创建新对象时,发生了哪些过程?
1.首先加载类信息(Person.class文件)到内存中的方法区。
2.在内存堆中开辟一块内存空间地址0x1122,作为类对象的地址。
3.为类的成员变量进行默认的初始化,即int = 0,float = 0.0,long = 0L,引用类型为null。
4.执行显式的初始化,即成员变量的显式赋值,int age = 1;
5.调用构造器进行最后的初始化,在方法区中有个常量池,“小倩”字符就在常量池中,假设地址为0x1133,则成员变量name指向了地址0x1133。
6.初始化完成后,new关键字操作结束,在内存栈中生成类的引用person指向类对象的地址0x1122,至此结束对象的创建并将变量名指向对象的地址。
(1)构造器和类名必须相同
(2)构造器没有返回值
构造器作用:
1.构造器用来初始化对象的值,且由系统调用
2.new 关键字的本质就是在调用构造器
注意:
1.当定义了有参构造器之后,无参构造器被覆盖了,需要显式的定义无参构造器,否则无法使用无参构造器。
2.如果编写类时,没有编写构造器,则初始化类时,系统会自动为每个类生成无参默认构造器:public Student() {}
3.在IDEA中,使用Alt + Insert 可以快速生成构造器
class Student {
int age;
String name;
//无参构造器,构造器必须与类名相同,且没有返回值
public Student() {}
//有参构造器
public Student(int age,String name) {
this.name = name;
this.age = age;
}
}
2.1 this关键字
JVM会给每个对象分配一个this指针,指向当前对象的地址。this指针的调用就是对当前对象的调用。哪个对象调用,this就指向哪个对象。
this关键字的作用:
为了让类的方法中与成员变量同名的形参与成员变量区别开来。
//比如上述Student类中的this.name就是对成员变量name的调用。 this.name -> 具体的某个Stduent对象.name;
this关键字在内存中的表示,指向对象本身的地址:
this使用的一些细节:
class Student {
int age;
String name;
//无参构造器,构造器必须与类名相同,且没有返回值
public Student() {}
//有参构造器1
public Student(int age) {
this.age = age;
}
//使用this的有参构造器
public Student(String name,int age) {
//调用当前对象的构造器,注意只能写在第一条语句处,否则会报错。
this(age);//只能写在第一句,且只能调用一个this();否则总一个不是在第一条,会报错。
this.name = name;
//this(age);如果写在这,报错:java: 对this的调用必须是构造器中的第一个语句
}
}
3.重载的定义
1.在一个类中,可以有同名函数,这些函数称为重载函数,但它们的形参个数不同或形参类型不同或形参位置不同,则属于方法重载。
2.在构造器中,不同的构造器就是方法重载的表现。
注意:但同名函数,形参个数、类型和形参l类型顺序相同,但形参变量名不同,或者返回值类型不同,不属于重载。
class Student {
public void study() {}
//下面的方法不属于重载,会被当成同名方法,从而导致编译报错,只有返回值类型不同,不算重载。
public int study() {}
//属于重载,形参的个数不同
public void study(String name,int age) {
System.out.print(name + age);
}
//属于重载,形参的类型不同
public void study(String name ,long age) {
System.out.print(name + age);
}
//属于重载,形参类型的顺序不同
public void study(long age ,String name) {
System.out.print(name + age);
}
//不属于重载,仅仅是形参名和返回值类型不同,不能算重载,会编译报错
public long study(long name ,String age) {
System.out.print(name + age);
return name;
}
}
4.可变参数
注意细节:
例子:
public int sum(int n1,int n2) {
return n1 + n2;
}
public int sum(int n1,int n2,int n3) {
return n1 + n2 + n3;
}
//多个同名方法sum,都是求输入的和,但输入的形参个数不同,此时可以使用可变参数...,避免写多个重复的无意义方法。
public int sum(int... nums) { //int...代表为可变参数,可以看作数组,nums.length可以获得可变参数的长度
int res = 0;
for (int n : nums) {
res += n;
}
return res;
}
//可变参数的实参可以是数组
int[] arr = new int[] {1,2,3};
//可以将arr数组赋给可变参数
sum(arr);
//一个方法中,只能出现一个可变参数,此种写法错误,会报错。
public int sum(int... nums,int... nums2){}
//如果形参列表中,不仅有可变参数,还有普通参数,则可变参数只能在最后
public int sum(String nums,,float f1,int... nums2){}
//public int sum(String... nums,float f1,int nums2){} 这种写法是错误的
5.作用域
//关于作用域,需要注意的一点是,局部变量不能直接使用,必须初始化,因为局部变量不会默认初始化,如果不初始化直接使用,会编译报错。
public int sum(int a) {
int i;//正确代码:int i = 1;
//会报错,如果直接使用,需要给i初始化,因为i是局部变量,没有默认值。
System.out.println(a + i);
}
作用域的细节:
//1.就近原则是说,如果在方法中,有跟全局变量同名的局部变量,则局部变量会将全局变量屏蔽。
int num = 0;
public int sum(int a) {
int num = 10;
//此处的输出为局部变量num = 10的值,即局部变量屏蔽了全局变量。
System,out.println(num);
}
class Student {
//全局变量可以使用修饰符,且能在本类中任何地方使用,或者在被public修饰时被其他类调用
public String name;
public void study(){
//局部变量不可以使用修饰符,public String name = "jack";会报错。且只能在方法内部使用。
String name = "jack";
System.out.println(name);
}
}



