类与对象:
-
基本概念:类是具有共性的对象的共性抽象,而对象是指一个具体的,可以使用的事 物。
对象一定来自于某个类
对象是类的实例化 -
类中的组成:属性(变量,描述每个对象的具体特点)
方法(对象可执行的过程) -
类的定义与使用:
类的定义:访问权限 class 类名{
定义数据(即属性);
定义方法;
}此时的方法不再有类直接调用,而需要由对象调用。
数据的定义:访问权限 数据类型 属性名;
方法的定义:访问权限 数据类型 方法名(形参){
方法体;
}
例如:People类的定义:
class People{
private String name;
private int age;
public People(String name,int age){
this.name = name;
this.age = age;
}
public void getInfo(){
System.out.println("姓名"+this.name +",年龄"+this.age);
}
}
-
对象的定义:类名称 对象名称 = new 类名称(实参);
以People类为例,我们可以产生如下People类的实例: People p1 = new People(); People p2 = new People(“小白”,10); 通过对象调用实例变量与实例方法: People p= new People(“小白”,10); //p.name 对象调用实例 System.out.println(p.name); //p.getInfo() 对象调用方法 System.out.println(p.getInfo());
-
对象的产生需要两步:
1.为对象分配内存空间
2.调用合适的构造函数我们先来看看怎样为对象分配内存空间:
我们先简单的将Java内存区域分为栈内存和堆内存两块区域:
栈内存(虚拟机局部变量表):存放的是局部变量(包含编译期可知的各种基本数据类型、引用对象-即堆内存地址),Java栈是与线程对应起来的,每当创建一个线程,JVM就会为这个线程创建一个对应的Java栈。
堆内存:保存的是真正的数据,即对象的属性信息。
下面通过代码和分析图来讲述是如何为对象分配内存的:
Class Student{ String name; int id; } public class Test{ public static void main(){ Student stu = new Student(); stu.name = “小白”; stu.id = 1; } }
内存图如下:
对象必须实例化后调用,否则会产生NullPointerEcception(运行时错误)
-
引用传递分析:
引用传递的本质:一块堆内存可以被多个栈空间所指向垃圾空间:没有任何栈内存指向的堆内存空间
所有的垃圾空间会不定期GC,GC会影响性能,所以无用的对象尽量少产生。
-
封装和构造方法:
private实现封装:要使内部操作对外部不可见(对象不可直接操作属性),可以用private进行封装。
使用private封装属性:
private String name; private int age;
此时要访问私有属性,按照java的设计原则必须提供两种方法:
1.setter方法:主要用于进行属性内容的设置与修改
2. getter方法:主要用于属性内容的取得class Student{ private String name; private int id; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public void getStudent() { System.out.println("姓名:"+name+",学号:"+id); } } public class Test { public static void main(String[] args) { Student stu = new Student(); stu.setName("小白"); stu.setId(1); stu.getStudent(); } }
private实现封装的最大特征在于:只允许本类访问,不允许外部类访问。
类的设计原则:编写类时,类中的所有属性必须使用private封装
属性若要被外部访问,必须定义setter、getter方法。 -
构造方法:
构造方法的定义:
1.方法名与类名同名
2.构造方法没有返回值类型
3.每个类中一定至少存在一个构造方法(没有明确定义,系统会自动生成无参构造,若类中定义了构造方法,则默认的无参构造将不再生成)为什么构造方法没有返回值类型?那是因为编译器根据程序结构来区分普通方法和构造方法的,所以在构造方法前不加返回值类型声明。
构造方法的调用和对象内存分配几乎时同时完成的,因此我们乐意利用构造方法来为类中的属性进行初始化构造(可避免多次setter方法调用)
构造方法的重载:
重载的特点:访问权限相同,函数名相同,参数列表相同,返回值不做要求
例如:
public People(){ System.out.println(“这是无参构造”); } public People(String name){ System.out.println(“这是带参构造”); }
现在我们可以看到,定义一个类的顺序:定义属性—>定义构造方法—>定义普通方法
-
匿名对象:
就是没有名字的对象,由于匿名对象不会有任何的栈空间指向,所以使用一次后就成为垃圾空间。
new People(“张三”,20).getPeople();
-
this关键字:
this关键字的三个用途:
this调用本类属性;
this调用本类方法;
this表示当前对象this调用本类属性:当参数与类中属性同名时,类中属性就无法被正确赋值,这是我们加上this关键字就可以给对象正确赋值。
class People{ private String name; private int age; public People(String name,int age){ name = name; age = age; } public String getPeo(){ return "姓名:" + name + ",年龄" + age; } public void print(){ System.out.println("=================="); } } public class Test { public static void main(String[] args) { People people = new People("小白",20); System.out.println(people.getPeo()); } }
上段代码我们可以发现输出为:姓名:null,年龄0
所以我们需要加上this
public People(String name,int age){ this.name = name; this.age = age; }
this调用本类方法:
1.调用普通方法:this.方法名称(参数)
2.调用构造方法:this(参数)class People{ private String name; private int age; public People(String name,int age){ this.name = name; this.age = age; //this调用普通方法 this.print(); } public String getPeo(){ return "姓名:" + name + ",年龄" + age; } public void print(){ System.out.println("=================="); } } public class Test { public static void main(String[] args) { People people = new People("小白",20); System.out.println(people.getPeo()); } }
this调用构造方法时请注意:
1.this调用构造方法的语句必须在语句首行;
2.使用this调用构造方法时,请留有出口this代表当前对象其实就是代表当前对象的引用:
例如:
class People{ public void printf() { System.out.println("[print]方法:" + this); } } public class Test { public static void main(String[] args) { People p1 = new People(); System.out.println("[main]方法:"+p1); p1.printf(); System.out.println("=============="); People p2 = new People(); System.out.println("[main]方法:"+p2); p2.printf(); } }
结果:
[main]方法:People@4554617c//后面这个数值为p1对象内存地址的哈希码
[print]方法:People@4554617c
==============
[main]方法:People@74a14482
[print]方法:People@74a14482 -
static关键字:
我们前面说到的传统属性所具备的特征就是保存在堆内存中,并且每个对象独享属性,如果想让这些属性成为共享的,那么只需在属性前加上static关键字即可。
static属性又称类属性,保存在全局数据区中,所有对象都可以进行该数据区的访问。
例如:
class People{ static String Country = "中国"; private String name; private int age; public People (String name,int age){ this.name = name; this.age = age; } public void getPeo() { System.out.println("姓名:" + this.name + ",年龄" + this.age + ",国籍:" + Country); } } public class Test { public static void main(String[] args) { People p1 = new People("小白",10); People p2 = new People("小黑",10); p1.getPeo(); p2.getPeo(); }
其内存分析如下:
访问static属性(类属性)应使用类名称.属性名所有的非static属性必须在对象实例化后使用,而static属性不受对象实例化控制
static类方法:类名.方法名直接访问
关于static方法有以下两点要注意:
所有的static方法不允许调用非static定义的属性和方法;
所有的非static方法允许访问static方法或属性使用static方法的目的只有一个:某些方法不希望收到对象的控制,即可在没有实例化对象的时候执行。