目录
✏️类定义和使用
类是Java程序的基本要素,一个Java应用程序就是由若干类所构成的。类声明的变量被称作对象变量,简称对象(就有点类似于C语言中的结构体)。
1.类的定义格式
格式:
// 创建类
class ClassName{
//field; 字段(属性) 或者 成员变量
//method; 行为 或者 成员方法
}
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。
例:
class Cat{
public String name;
public String color;
//猫的叫声
public void meow() {
System.out.println(name + ":喵喵喵~");
}
//行为
public void behavior() {
System.out.println(name + ":舔爪子");
}
}
问题:为什么在方法中能直接用 name 变量呢?
答:name是定义在方法外面的,就类似于C语言中的全局变量,整个类里的方法都可以直接用该变量。(特殊的情况除外,如加了static的方法 等,static关键字的详细介绍后面会更新)。
需要注意的:
//可以在声明的同时指定变量的初值
class A{
int a = 12;
float b = 12.33f;
}
//以下是错误的用法
class A{
int a;
float b;
a = 12; //非法
b = 12.33f; //非法
}
注意:
- 在声明成员变量时如果没有指定初始值,Java编译器会为其指定相应的默认值。
- 类名注意采用大驼峰定义(首字母大写)
- 一般一个文件当中只定义一个类。
- main方法所在的类一般要使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)。
- public修饰的类必须要和文件名相同。
- 成员前写法暂时统一为public,方法暂时不带 static 关键字。(关于static的详细介绍会在后续更新)
2.类的实例化
类是用户自定义了一个新的类型,比如上述的:Cat类;用 类 类型创建对象的过程,称为类的实例化。
- 对象的声明
类的名字 对象的名称;
例:
Cat c;
- 为声明的对象分配变量
使用new运算符来创建对象;
public class Main{
public static void main(String[] args) {
Cat c = new Cat();
c.name = "小白";
c.color = "白色";
c.behavior();
c.meow();
Cat c2 = new Cat();
c2.name = "小黑";
c2.color = "黑色";
c2.behavior();
c2.meow();
}
}
运行结果:
小白:舔爪子
小白:喵喵喵~
小黑:舔爪子
小黑:喵喵喵~
注意:
- new 关键字用于创建一个对象的实例。
- 使用“ . ”来访问对象中的属性和方法。
- 同一个类 类型可以创建多个实例。
3.类的内存模型
类的信息放在了方法区、对象的引用存放在栈中,对象的实例存放在堆中。
JavaSE语法(5)——【数组(基本类型变量与引用类型变量的区别、二维数组、二维数组打印、jvm的内存分布……)】_虾料的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127608985?spm=1001.2014.3001.5501关于方法区、栈、堆 ,上面文章有介绍👆。
有如下代码:
public class Main{
public static void main(String[] args) {
Cat c = new Cat();
c.name = "小白";
c.color = "白色";
c.meow();
}
}
class Cat{
public String name;
public String color;
//猫的叫声
public void meow() {
System.out.println(name + ":喵喵喵~");
}
}
- 当程序开始时,Main类里的信息(成员变量、成员方法)会存到方法区。
- 当开始执行main方法时,栈里就会开辟一个空间来装main方法(入栈)。
- 当执行到 Cat c = new Cat() 时,方法区就会加载Cat类的信息,同时在堆中创建Cat的实例,栈里的 c ,存储了堆里的Cat实例的地址;堆里的Cat实例中的方法存储了方法区里的方法的地址。
- 对成员变量进行赋值后(对字符串赋值涉及到常量池,常量池详细内容后面更新),执行到c.meow()时,通过地址获取到方法区里的meow方法的信息,然后在栈里开辟一个空间。
✏️this引用
1. 引入
class Student{
public int age;
public int height;
public void set(int a, int h){
age = a;
height = h;
}
public void print(){
System.out.println("age: " +age + " height: " + height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
//输入年龄、身高
s1.set(18,180);
s2.set(20,184);
//打印
s1.print();
s2.print();
}
}
结果:
age: 18 height: 180
age: 20 height: 184
输出没问题,但是我们把set()里的参数改一下:
class Student{
public int age;
public int height;
//改成 age height
public void set(int age, int height ){
age = age;
height = height;
}
public void print(){
System.out.println("age: " +age + " height: " + height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
//输入年龄、身高
s1.set(18,180);
s2.set(20,184);
//打印
s1.print();
s2.print();
}
}
这时Student里的成员变量的值是什么?
结果:
age: 0 height: 0
age: 0 height: 0
发现age与height的值并没有改变,是因为set的形参与成员变量名相同了,这时set方法里的age与height不算Student的成员变量,而是算作形参了,要避免这一现象,就可以用this关键字。
2.什么是this引用
this表示某个对象,this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。
以上面的例子:
class Student{
public int age;
public int height;
//改成 age height
//加了this
public void set(int age, int height ){
this.age = age;
this.height = height;
}
public void print(){
System.out.println("age: " +this.age + " height: " + this.height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
//输入年龄、身高
s1.set(18,180);
s2.set(20,184);
//打印
s1.print();
s2.print();
}
}
结果:
age: 18 height: 180
age: 20 height: 184
注意:
- this的类型:对应类类型引用,即,哪个对象调用就是哪个对象的引用类型。
- this只能在"成员方法"中使用(加了static的方法不行,后续更新)。
- 在"成员方法"中,this只能引用当前对象,不能再引用其他对象。
- this也可以调用该类的方法,就跟调用变量一样。
- this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收。
例:在set方法的形参列表里加一个“Student this”。
结果:
能编译过,说明this就是本类的引用。
✏️构造方法
1.概念及用法
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次,构造方法的作用就是对对象中的成员进行初始化。
class Student{
public int age;
public int height;
// 构造方法:
// 名字与类名相同,没有返回值类型,设置为void也不行
// 一般情况下使用public修饰
// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
public Student(int age,int height) {
System.out.println("构造方法被调用了!!!");
this.age = age;
this.height = height;
}
public void print(){
System.out.println("age: " +age + " height: " + height);
}
}
public class Main{
public static void main(String[] args) {
//输入初始值
Student s1 = new Student(18,182);
s1.print();
}
}
结果:
构造方法被调用了!!!
age: 18 height: 182
注意:
- 构造方法的参数有几个,new的时候就要输入几个参数,否则会报错。
- 当没有写构造方法的时候,编译器会自动生成一个无参数的构造方法(并且不会显示),如果写了就不会生成,这也是为什么上一条会报错的原因。
- 构造方法可以重载!当我们既想在new的时候不输入参数不报错,又想输入参数,那么就可以重载构造方法。
class Student{
public int age;
public int height;
// 构造方法:
// 名字与类名相同,没有返回值类型,设置为void也不行
// 一般情况下使用public修饰
// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
public Student() {
System.out.println("无参的构造方法被调用了!!!");
//也可以在这里对age 和 height 赋值
}
public Student(int age,int height) {
System.out.println("有参的构造方法被调用了!!!");
this.age = age;
this.height = height;
}
public void print(){
System.out.println("age: " +this.age + " height: " + this.height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
s1.print();
Student s2 = new Student(18,180);
s2.print();
}
}
结果:
无参的构造方法被调用了!!!
age: 0 height: 0
有参的构造方法被调用了!!!
age: 18 height: 180
2.this引用在构造方法中的应用
this可以调用其他构造方法,格式:" this() ",因为this就是Student的引用,可以把this看作Student。
class Student{
public int age;
public int height;
public Student() {
this(12,181);
}
public Student(int age,int height) {
System.out.println("有参的构造方法被this调用了!!!");
this.age = age;
this.height = height;
}
public void print(){
System.out.println("age: " +this.age + " height: " + this.height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
s1.print();
}
}
结果:
有参的构造方法被this调用了!!!
age: 12 height: 181
注意:
- this(...)必须是构造方法中第一条语句,不然会报错。
- 不能形成环。
✏️封装
1.访问限定符
在前面我们都是用public来修饰方法、变量、类,这有什么玄机呢?
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:
- public:可以理解为一个人的外貌特征,谁都可以看得到。
- default(什么都不写的时候的默认权限):对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了。
- private:只有自己知道,其他人都不知道。
注意:
- protected主要是用在继承中。(更新继承的时候再来详细介绍,本篇就不介绍了)
- default 权限指:什么都不写时的默认权限!!!
- 访问权限除了可以限定类中成员(包括方法)的可见性,也可以控制类的可见性。
2.private
看下面代码:
class Student {
private int age;
private int height;
public void print() {
System.out.println("age: " + this.age + " height: " + this.height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
s1.age = 18;
s1.height = 184;
}
}
结果:
可以看到报错了,是因为private只能在同一个类中才能被访问到,那么有什么方法可以改变age 和 height 呢?
我们可以用public修饰的方法来修改其值,这其实体现着封装的思想。
class Student {
private int age;
private int height;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void print() {
System.out.println("age: " + this.age + " height: " + this.height);
}
}
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
s1.setAge(18);
int age = s1.getAge();
System.out.println(age);
s1.setHeight(180);
int height = s1.getHeight();
System.out.println(height);
s1.print();
}
}
结果:
18
180
age: 18 height: 180
我们可以用setAge()、setHeight()来赋值,getAge()、getHight()来取值。
3.包
3.1 概念
为了更好的管理类,把多个类收集在一起成为一组,称为软件包。
包是Java语言有效地管理类的一个机制。在不同Java源文件中可能出现名字相同的类,如果用户想区分这些类,就需要使用包名。使用包名可以有效地区分名字相同的类,当不同Java源文件中的两个类的名字相同时,它们可以通过隶属于不同的包来相互区分。
3.2 导入包中的类:import
Java 中已经提供了很多现成的类供我们使用。例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date类。
public class Main{
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
但是这样操作太复杂了,我们直接用import来导入包:
import java.util.Date;
public class Main{
public static void main(String[] args) {
Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
如果我们还想使用 util 里其它的类,比如:Arrays类。这时可以用“ * ”:
import java.util.*;
public class Main{
public static void main(String[] args) {
Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
int[] arr = {5,4,3,2,1};
Arrays.sort(arr);
}
}
- 注意:这样使用也有风险!!!
import java.util.*;
import java.sql.*;
public class Main{
public static void main(String[] args) {
Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
结果:
在util 和 sql 中都有Data这个类,这时会冲突,这就需要写详细一点了。
4. 什么都不写的时候的默认权限(default)
创建了两个包、并在里面写了不同的类:
demo2包:
package demo2;
public class Student {
//什么修饰符都没写
int age;
int height;
public void print() {
System.out.println("age: " + this.age + " height: " + this.height);
}
}
demo1包:
package demo1;
//导包中的类
import demo2.Student;
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
s1.age = 18;
s1.height = 180;
s1.print();
}
}
结果:
同一个包 demo1:
结果(代码一样):
age: 18 height: 180
修饰类的情况:
demo2:
package demo2;
//该类没有写修饰符,即为默认的权限
class Student {
int age;
int height;
public void print() {
System.out.println("age: " + this.age + " height: " + this.height);
}
}
demo1:
package demo1;
import demo2.Student;
public class Main{
public static void main(String[] args) {
Student s1 = new Student();
s1.age = 18;
s1.height = 180;
s1.print();
}
}
结果:
总结:什么都不写的时候的默认权限(default),只有在同一个包中才能被访问到。不只是变量,修饰符加在方法、类上都是一样的,而public权限在什么地方都能被访问,就不介绍了。