目录
一、类的定义
1、在java中定义类需要用到class关键字
class ClassName{
filed; //成员变量(属性)
method; //成员方法
}
【注意】
- 类名采用大驼峰定义
- 一般一个文件只能定义一个类
- main方法所在的类一般要使用public修饰
- public修饰的类必须与文件名相同
- 不能随便修改public修饰的类的名称
2、类的使用(实例化)
定义类,就相当于在计算机中定义了一种新的类型,用定义的类类型创建对象的过程,称为类的实例化。
//定义了一个狗类
class PetDog {
public String name;//名字
public String color;//颜色
public void barks() {
System.out.println(name + ": 旺旺旺~~~");
}
public void wag() {
System.out.println(name + ": 摇尾巴~~~");
}
}
public class Main{
public static void main(String[] args) {
PetDog dogh = new PetDog(); //通过new实例化对象
dogh.name = "阿黄";
dogh.color = "黑黄";
dogh.barks();
dogh.wag();
}
【注意】
- new关键字用于创建对象的实例
- 使用【类名.成员/方法】来访问对象
- 同一个类可以创建多个实例
二、this引用
java编译器给每个“成员方法”增加了一个隐藏的引用类型参数(this),该引用参数指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。(this引用的是调用成员方法的对象)
this的三种用法:
- this.成员变量(成员变量不能是静态的)
- this.成员方法(成员方法不能是静态的)
- this()调用其他的构造方法(必须放在第一行)
对于以下代码:
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d) {
year = y;
month = m;
day = d;
}
public void printDate() {
System.out.println(year + "/" + month + "/" + day);
}
public static void main(String[] args) {
// 构造三个日期类型的对象 d1 d2 d3
Date d1 = new Date();
Date d2 = new Date();
Date d3 = new Date();
// 对d1,d2,d3的日期设置
d1.setDay(2020, 9, 15);
d2.setDay(2020, 9, 16);
d3.setDay(2020, 9, 17);
// 打印日期中的内容
d1.printDate();
d2.printDate();
d3.printDate();
}
}
(1)形参名与成员变量名相同
根据局部变量优先原则,方法中的year都为方法的参数year,次数编译无法通过,需要通过this来调用类中的成员变量。
public void setDay(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
(2)当三个对象都在调用方法setDate和printDate时,函数不能确定打印的是那个对象的数据,此时需要this来确定打印对象。
public void printDate(){
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
【注】
- this只能在“成员方法”中使用
- this的类型:对应类的引用类型
- 在“成员方法”中,this只能引用当前对象,不能引用其它对象,具有final(相当于C++中的const)属性
- this不能为空
三、构造方法及对象的初始化
1、构造方法
是一种特殊的成员方法。名字必须与类名相同,创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
【特性】
- 名字必须与类名相同。
- 没有返回值类型,设置为void也不行。
- 构造方法至少一个,可以是多个。
- 创建对象时编译器自动调用,并且在对象的生命周期中只调用一次。
- 构造方法可以重载。(可以根据自己的需求提供不同参数的构造方法)
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法
public Date() {
this.year = 1900;
this.month = 1;
this.day = 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
调用对象时,根据对象的参数来调用构造方法。
- 没有定义构造方法时,编译器会生成一个默认的构造方法,生成的构造方法一定是无参的。一旦用户定义了构造方法,编译器便不再生成。
- 可以在一个构造方法中使用this调用另一个构造方法。
public class Date {
public int year;
public int month;
public int day;
//不带参数的构造方法
public Date(){
this(1900, 1, 1);
System.out.println(year);
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
【注】
- this必须是构造方法中的第一条语句。
- 不能形成环
- 绝大多数情况下使用public修饰,特殊情境下会被private修饰
2、对象的初始化
(1)默认初始化
局部变量在使用时必须要初始化,而成员变量不用。因为new会调用构造方法,给对象中各个成员赋值。
new关键字在虚拟机中的工作:
- 检查对象对应的类是否加载
- 为对象分配内存空间
- 处理并发问题(多个线程同时申请空间,JVM要保证给对象分配的空间不冲突)
- 初始化所分配的空间
- 设置对象头信息
- 调用构造方法,给对象中各个成员赋值
(2)就地初始化
在声明成员变量时,直接给出初始值。
四、封装
面向对象程序的三大特性:封装、继承、多态。
封装:从语法层次来说,就是将字段或方法用private进行修饰,使其只能在当前类使用,起到了封装的作用
【访问限定符】
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,而访问权限用来控制方法或者字段能否直接在类外使用。java中提供了四种访问权限符:
范围 | private | default | protected | public |
同一个包的同一个类 | √ | √ | √ | √ |
同一个包的不同类 | √ | √ | √ | |
不同包中的子类 | √ | √ | ||
不同包中的非子类 | √ |
对于private修饰的变量,我们可以通过get和set方法来获取和操作它。
(右键→Generate→GetterandSetter)即可
public class Computer {
private String cpu;// cpu
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
}
【说明】
- protected主要用在继承中
- default权限:什么都不写时的默认权限
- 访问权限除了可以限定类中成员的可见性,也可以控制类的可见性
【注】一般情况下,成员变量设置为private,成员方法设置为public
五、包
1、包的概念
软件包:为了更厚的管理类,把多个类收集在一起成为一组,称为包。
在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
2、导入包中的类
使用import语句导入包。
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
如果需要使用 java.util 中的其它类,可以使用 import java.uti.*
对于以下情况:
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
System.out.println(date.getTime());
}
}
两个包中都存在Date类,此时我们需要引用完整的类名,否则编译器不知道调用哪个包下的Date类。
3、自定义包
【基本规则】
- 在文件的最上方加上一个package语句,指定该代码所在的包
- 包名尽量指定为唯一的名字,通常用公司域名的颠倒形式
- 报名要和代码路径相匹配
- 如果一个类没有package语句,则该类被放在一个默认包中
【新建包】右键src→新建→包
【新建类】右键包名→新建→类
4、常见的包
- Java.lang:系统常见基础类(String 、Object)编译器会自动导入
- java.lang.reflect:java反射程序包
- java.net:进行网络编程开发包
- java.sql:进行数据库开发的支持包
- java.util:java提供的工具程序包
- java.io:I/O编程开发包
六、static成员
在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,不属于某个具体的对象,是所有的对象共享的。
静态的成员变量和成员方法都是不依赖于对象的
1、static修饰成员变量
【静态成员变量特性】
- 不属于某个具体的对象,是类的属性,所有对象所共享的,不存储在某个对象的空间中
- 可以通过对象访问,也可以通过类访问,推荐使用类访问
- 类变量存储在方法区中
- 生命周期伴随类的一生(随类的加载创建,类的卸载销毁)
2、静态成员方法
【静态成员方法特性】
- 不属于某个具体的对象,是类方法
- 通过 类名.静态方法名(……)方式调用
- 不能在静态方法中访问任何非静态成员变量(静态方法没有隐藏的this引用参数)
public static String getClassRoom(){
System.out.println(this);
return classRoom;
}
// 编译失败:Error:(35, 28) java: 无法从静态上下文中引用非静态 变量 this
public static String getClassRoom(){
age += 1;
return classRoom;
}
// 编译失败:Error:(35, 9) java: 无法从静态上下文中引用非静态 变量 ag
- 静态方法中不能调用任何非静态方法,(非静态方法有this参数,在静态方法中调用时无法传递)
七、代码块
【注】代码块的执行顺序:
父类静态代码块(只执行一次)➡️子类静态代码块→父类实例代码块→父类构造方法➡️子类实例代码块➡️子类构造代码快
public class Student{
private String name; //实例成员变量
private String gender;
private int age;
private double score;
private static String classRoom;
//实例代码块
{
this.name = "bit";
this.age = 12;
this.gender = "man";
System.out.println("I am instance init()!");
}
// 静态代码块
static {
classRoom = "bit306";
System.out.println("I am static init()!");
}
public Student(){
System.out.println("I am Student init()!");
}
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}
1、普通代码块:定义在方法中的代码块
2、构造代码块:定义在类中的代码块。也称实例代码块,一般用于初始化实例成员变量
定义在类的内部,和构造方法同级。
3、静态代码块:使用static修饰的代码块。一般用于初始化静态成员变量
【注】
- 无论生成多少个对象,静态代码块只执行一次
- 静态成员变量是类的属性,在JVM加载类是开辟空间并初始化
- 如果一个类包含多个静态代码块,在编译代码时,编译器会按照定义的先后顺序合并,最终放在生成的<>方法中,该方法在加载类时调用,并且只调用一次。
- 实例代码块只有在创建对象时才会执行
八、对象的打印
当类中有多个成员变量,我们需要打印对象中内容,此时应该重写toString方法。
(鼠标右击→Generate→toString())即可
public class Person {
String name;
String gender;
int age;
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
@ Override
public String toString() {
return "[" + name + "," + gender + "," + age + "]";
}
public static void main(String[] args) {
Person person = new Person("Jim","男", 18);
System.out.println(person);
}
} // 输出结果:[Jim,男,18]
当我们调用System.out.println();时,
编译器会默认调用Object的toString方法,如果当前类对toString方法重写,则会调用自己的toString方法。(重写需要用到@Override,起到检查的作用)
九、内部类
在java中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。
1、实例内部类
定义在类中,未被static修饰的类
【注】
- 创建内部类对象
OutClass.InnerClass innerClass=new OutClass().new InnerClass();
外部类.内部类 变量=外部类对象的引用.new 内部类()
- 实例内部类中,创建的成员变量不能是static的,如果定义只能是static final
- 如果内部类和外部类具有相同名称的成员,优先访问的是内部类的
- 如果需要访问外部类的同名成员变量,必须 (外部类名称.this.同名成员)
2、静态内部类
被static修饰的内部成员类
【注】
- 创建静态内部类对象
OutClass.InnerClass innerclass=new OutClass.InnerClass();
- 在创建静态内部类对象时,不需要先创建外部类对象
- 成员内部类,经过编译之后会生成独立的字节码文件,命名格式为:外部类名称.内部类名称
- 在静态内部类中只能访问外部类的静态成员
3、局部内部类
定义在外部类的方法中,这种内部类只能在其定义的位置使用,一般使用的非常少
【注】
- 局部内部类只能在定义的方法体内使用
- 不能被public、static等修饰符修饰
- 几乎不会使用