Java类与对象概述(一)
1. 面向对象特征(三大基本特征)
面向对象最大特征:对现实生活可以进行抽象。举个简单的例子,把一个大象关进冰箱里,对于面向过程而言,首先把冰箱门打开,其次把大象放进去,最后关上冰箱门;但面向对象始终关心的是大象这个实体,不关心这些步骤。
- 封装:把客观事物封装成抽象的类,并且类把自己的方法和数据,只让可信的类或者对象操作,对不可信的信息进行隐藏。即就是,内部操作对外部而言不可见
- 继承:实现现有类的功能,并对原有类的功能进行扩展创新
- 多态:多态就是一个类实例的相同方法在不同情形有不同表现形式
2. 类与对象的定义与使用
2.1 基本概念
- 类:具有相同事物的集合
- 对象:一个具体的、可以使用的事物
- 类的组成:属性和方法
2.2 定义和使用
例如:一个Person类的定义
class Person{
public String name; //属性
public int age; //属性
public Person(String name, int age){ //构造方法
this.name = name; //this.xxx表示当前类的属性
this.age = age;
}
public String getPersonInformation(){ //普通方法
return "姓名:"+this.name+",年龄:"+this.age;
}
}
有了类,即可以定义对象,语法:类名称 对象名称 = new 类名称();
以上述Person类为例,用来产生Person类的一个实例
Person person = new Person("张三", 20); //new关键字,代表开辟了一块内存
Person person1 = new Person("李四", 21);
有了对象,我们可以用对象调用实例属性(public修饰)和方法
Person person = new Person("张三", 20);
System.out.println(person.name);
System.out.println(person.getPersonInformation());
2.3 对象内存分析
Java内存分为栈内存和堆内存
- 栈内存:存放的是局部变量(基本数据类型,对象引用)
- 堆内存:保存真正的数据。即对象的属性信息
比如上述的例子中,Person person = new Person("张三", 20);
,new关键字,表示在堆内存分配了内存,并且产生了Person类的对象person引用这块内存。
刚开始堆内存中:name = null
, age = 0
,栈中的person(0x0001)指向这块堆内存
当构造方法一执行结束,name = "张三"
, age = 20
,
针对以上,注意的几点如下:
- 对象(引用数据类型)必须在实例化后调用,否则会产生NullPointException(运行错误),但编译不会出错
- 垃圾空间:没有任何栈内存指向的堆空间
- 所有的垃圾空间会不定期GC,GC会影响性能,所以要减少无用对象的产生
3. 封装和构造方法
3.1 用private实现封装
让内部操作对外部不可见,即不能用对象直接操作属性,可以使用private
private String name;
private int age;
一旦使用了private,要访问私有属性时,有两种方法
- setter方法:主要对属性内容进行修改与设置
- getter方法:获取属性内容
例如:扩展上述Person类的内容
class Person{
private String name; //只允许本类访问,不允许外部类访问
private int age;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public String getPersonInformation(){
return "姓名:"+this.name+",年龄:"+this.age;
}
}
public class TestPerson{
public static void main(String[] args){
Person person = new Person();
person.setName("张三");
person.setAge(20);
System.out.println(person.getPersonInformation());
}
}
类的设计原则:
- 编写类时,类中的所有属性必须使用private封装
- 属性如果要被外部访问,必须定义setter、getter方法
3.2 构造方法
产生对象类名称 对象名称 = new 类名称();
其实构造方法就是使用关键字new实例化新对象时来进行调用的操作方法
对构造方法的定义,需要遵循以下原则:
- 1.方法名称必须与类名称相同
- 2.构造方法没有返回值类型声明
- 3.每一个类中至少存在一个构造方法(没有明确定义,系统自动生成一个无参构造)
构造方法无返回值,为什么没有void声明?分析如下:
- 1.属性是在对象开辟堆内存时开辟的空间
- 2.构造方法是在使用new后调用的
- 3.普通方法是在空间开辟了、构造方法执行之后多次调用的
public void Person(){} //命名不标准的普通方法
public Person(){} //无参构造方法
因此,编译器是根据程序结构来区分普通方法与构造方法,所以构造方法没有返回值类型声明
若类中定义了构造方法,则默认的无参构造将不再生成
比如上述中的Person类:
public Person(String name, int age){ //两个参数
this.name = name;
this.age = age;
}
构造方法的调用和内存分配几乎是同步完成的,因此我们可以利用构造方法来为类中的属性进行初始化操作(避免多次setter调用)
3.3 构造方法重载
- 构造方法按照参数个数升序或者降序
public Person(String name){
this.name = name;
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
3.4 匿名对象
- 没有任何栈空间指向,使用一次就成为垃圾空间
class Person{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public void getPersonInformation(){
System.out.println("姓名:"+this.name+",年龄:"+this.age);
}
}
public class TestPerson{
public static void main(String[] args){
new Person("张三", 20).getPersonInformation(); //匿名对象
}
}
4. this关键字
this关键字有三个用途:
- this调用本类属性
- this调用本类方法
- this表示当前对象
4.1 this调用本类属性
在上述的Person类中,当参数与类中属性同名时,类中的属性无法被正确赋值。因此加上this关键字可以正确的给对象属性赋值
this.name = name;
this.age = age;
只要在类中访问类中的属性,一定要加上this关键字
4.2 this调用本类方法
- this调用普通方法:this.方法名称(参数)
- this调用构造方法:this(参数)
举例:this调用普通方法
class Person{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
this.print(); //this调用普通方法
}
public String getPersonInformation(){
return "姓名:"+this.name+",年龄:"+this.age;
}
public void print(){
System.out.println("**************");
}
}
public class TestPerson{
public static void main(String[] args){
Person person = new Person("张三", 20);
System.out.println(person.getPersonInformation());
}
}
调用普通方法不需要加上this也可以正常调用,但加上可以区分方法的定义来源
举例:this调用构造方法
class Person{
private String name;
private int age;
public Person(){
System.out.println("*******构造方法********");
}
public Person(String name){
this(); //调用本类无参构造
this.name = name;
}
public Person(String name, int age){
this(name); //调用本类有参构造
this.age = age;
}
public String getPersonInformation(){
return "姓名:"+this.name+" 年龄:"+this.age;
}
}
public class TestPerson{
public static void main(String[] args){
Person person = new Person();
System.out.println(person.getPersonInformation());
Person person1 =new Person("张三");
System.out.println(person1.getPersonInformation());
Person person2 = new Person("李四", 18);
System.out.println(person2.getPersonInformation());
}
}
/*
********构造方法************
姓名:null 年龄:0
********构造方法************
姓名:张三 年龄:0
********构造方法************
姓名:李四 年龄:18
*/
在用this调用构造方法时,语句必须在构造方法首行
4.3 this表示当前对象
举例:this表示当前对象
class Person{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public void print(){
System.out.println("PRINT方法"+this);
}
}
public class TestPerson{
public static void main(String[] args){
Person person = new Person("张三", 20);
person.print();
System.out.println("MAIN方法"+person);
}
}
/*
PRINT方法Person@15db9742
MAIN方法Person@15db9742
*/
5. static关键字
5.1 static类属性
- 传统属性保存在堆内存中,且每个对象独享属性
- static属性又称类属性,保存在全局数据区的内存中,所有对象都可以进行数据区的访问
举例:含有static属性
class Person{
private String name;
private int age;
private static String country = "China";
public Person(Stirng name, int age){
this.name = name;
this.age = age;
}
public String getPersonInformation(){
return "姓名:"+this.name+",年龄:"+this.age+",国家:"+Person.country;
}
}
public class TestPerson{
public static void main(String[] args){
Person person = new Person("张三", 20);
System.out.println(person.getPersonInformation());
}
}
//姓名:张三,年龄:20,国家:China
结论:
- 访问static属性应使用类名称.属性名
- 所有非static属性(实例变量)必须在对象实例化使用,而static属性不受对象实例化控制
- 当我们修改country属性时,所有属性值都同步此属性值
5.2 static类方法
举例:static方法
class Person{
private String name;
private int age;
private static String country = "China";
public Person(Stirng name, int age){
this.name = name;
this.age = age;
}
public static void setCountry(String country){
Person.country = country; //此处不能使用this.country,静态方法不能访问非静态属性
}
public String getPersonInformation(){
return "姓名:"+this.name+",年龄:"+this.age+",国家:"+this.country; //此处的Person.country可以用this.country替换,非静态方法可以访问静态属性
}
}
public class TestPerson{
public static void main(String[] args){
Person person = new Person("张三", 20);
System.out.println(person.getPersonInformation());
Person.setCountry("American");
System.out.println(person.getPersonInformation());
}
}
/*
姓名:张三,年龄:20,国家:China
姓名:张三,年龄:20,国家:American
*/
结论:
- 所有的static方法不允许调用非static定义的属性或方法
- 所有的非static方法允许访问static方法或属性
- main方法是一个特殊的static方法