首页 >> 大全

2.类和对象的定义与使用

2023-11-18 大全 28 作者:考证青年

类名称 对象名称=new 类名称();

格式二:先声明对象,然后实例化对象

类名称 对象名称=null;

对象名称=new 类名称();

例:

class Dog{//创建一个狗类public String color;public String name;public int age;public void barks(){System.out.println(name+":汪汪汪~");}public void wag(){System.out.println(name+":摇尾巴~");}}
public class J1103 {public static void main(String[] args) {Dog dog1 = new Dog(); //通过new实例化对象dog1.name = "阿黄";dog1.color = "黄";dog1.barks();dog1.wag();Dog dog2 = null;//这里代表dog2这个引用不指向任何对象dog2=new Dog();dog2.name = "阿黑";dog2.color = "黑";dog2.barks();dog2.wag();}
}

定义了一个类,就相当于在计算机中定义了一种新的类型。

上述例子用类 类型创建对象的过程,称为类的实例化。

当实例化了以后,狗这个类就一个实体了,是某只叫阿黄的黄狗,会汪汪汪和摇尾巴。

运行结果:

关于类的注意事项:

1. 一般一个文件当中只定义一个类

2. main方法所在的类一般要使用修饰(注意:默认会在修饰的类中找main方法)

3. 修饰的类必须要和文件名相同

4. 不要轻易去修改修饰的类的名称,如果要修改,就这样修改:

3.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 d3Date d1 = new Date();Date d2 = new Date();Date d3 = new Date();
// 对d1,d2,d3的日期设置d1.setDay(2020, 9, 15);d2.setDay(2020, 9, 16);}}

以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打印,代码整体逻辑非常简单,没有任何问题。

但是细思之下有以下两个疑问:

1. 形参名不小心与成员变量名相同:

public void setDay(int year, int month, int day){year = year;month = month;day = day;
}

2. 三个对象都在调用和函数,但是这两个函数中没有任何有关对象的说明,和函数如何知道打印的是那个对象的数据呢?

这时候就需要this引用来发挥作用了 。

1.什么是this引用

this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。

例:

public class Date {public int year;public int month;public int day;public void setDay(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}public void printDate(){System.out.println(this.year + "/" + this.month + "/" + this.day);}
}

注意:this引用的是调用成员方法的对象。

public static void main(String[] args) {Date d = new Date();d.setDay(2020,9,15);d.printDate();
}

现在知道了this的重要性,为了保险起见,无论当前代码需不需要用this,我们都应当主动在能加的地方加上this。

2.this引用的特性

1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型

2. this只能在"成员方法"中使用

3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象

4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收

4.对象的构造及初始化 4.1 构造方法的概念及作用

1.构造方法:(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

2.作用:用来给成员变量进行初始化,也就是产生对象

3.使用new关键字产生一个对象时,大致分为以下两步:

(1) 为对象分配内存(空间大小由该类中成员变量的属性决定)

(2) 调用合适的构造方法来初始化当前对象中的成员变量

4.2构造方法特性:

1. 名字必须与类名相同

2. 没有返回值类型,设置为void也不行

3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)

4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)

例:

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;}public void printDate(){System.out.println(year + "-" + month + "-" + day);}public static void main(String[] args) {Date d = new Date();d.printDate();}
}

上述两个构造方法:名字相同,参数列表不同,因此构成了方法重载

5.一个类中至少存在一个构造方法,如果用户没有显式定义,编译器会生成一份默认的构造方法(编译器不会显示出来),生成的默认构造方法一定是无参的

public class Date {public int year;public int month;public int day;public void printDate(){System.out.println(year + "-" + month + "-" + day);//这就是编译器默认生成的无参构造方法,不会显示出来/*public Date(){}*/}public static void main(String[] args) {//当创建对象时默认调用该类的构造方法Date d = new Date();d.printDate();
}
}

6.如果用户自己定义了构造方法,编译器则不再生成。

public class Date {public int year;public int month;public int day;public Date(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}public void printDate(){System.out.println(year + "-" + month + "-" + day);}public static void main(String[] args) {// 如果编译器会生成,则生成的构造方法一定是无参的// 则此处创建对象是可以通过编译的// 但实际情况是:编译器报错Date d = new Date();d.printDate();}
}/*
Error:(26, 18) java: 无法将类 extend01.Date中的构造器 Date应用到给定类型;
需要: int,int,int
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
*/

7. 构造方法中,可以通过this调用其他构造方法来简化代码

public class Date {public int year;public int month;public int day;// 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复// 此处可以在无参构造方法中通过this调用带有三个参数的构造方法// 但是this(1900,1,1);必须是构造方法中第一条语句public Date(){//System.out.println(year); 注释取消掉,编译会失败this(1900, 1, 1);//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;}
}

不过这么做有两点需注意:

1.this(...)必须是构造方法中第一条语句

2.不能形成环,否则构造方法会死循环

public Date(){this(1900,1,1);
}
public Date(int year, int month, int day) {this();
} /* 
报错:
无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
编译报错:Error:(19, 12) java: 递归构造器调用
*/

4.3 构造方法的初始化

构造方法的初始化一种有两种方式:默认初始化和就地初始化

1.默认初始化

public class Date {public int year;public int month;public int day;public Date(int year, int month, int day) {// 成员变量在定义时,并没有给初始值, 为什么就可以使用呢?System.out.println(this.year);System.out.println(this.month);System.out.println(this.day);}public static void main(String[] args) {// 此处a没有初始化,编译时报错:// Error:(24, 28) java: 可能尚未初始化变量a// int a;// System.out.println(a);Date d = new Date(2021,6,9);}
}

要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情

Date d = new Date(2021,6,9);

在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:

1. 检测对象对应的类是否加载了,如果没有加载则加载

2. 为对象分配内存空间

3. 处理并发安全问题

比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

数据类型

默认值

byte

char

'\u0000'

short

int

long

0L

false

float

0.0f

0.0

null

4. 初始化所分配的空间

5. 设置对象头信息(本文暂不介绍)

6. 调用构造方法,给对象中各个成员赋值

2.就地初始化

在声明成员变量时,就直接给出了初始值。

public class Date {public int year = 1900;public int month = 1;public int day = 1;public Date(){}public Date(int year, int month, int day) {}public static void main(String[] args) {Date d1 = new Date(2021,6,9);Date d2 = new Date();}
}

注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中

5.封装

何为封装呢?简单来说就是套壳屏蔽细节

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

为什么要封装?

封装是出于对代码的安全性考虑

5.1 访问限定符

Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

范围

同一包中的同一类

同一包中的不同类

不同包中的子类

不同包中的非子类

:公共的,在当前程序(项目)中都是可见并且可以使用的

:默认的,对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了

:受保护的,继承访问权限

:私人的,只在当前类可见,出了类{ },对外就完全隐藏了,外部不知道有其存在

这里主要说这个访问限定符

class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void sleep(){System.out.println(this.name+"正在睡觉");}}
public class Test {public static void main(String[] args) {Student student=new Student("张三",10);//当name和age被private修饰后这么做会报错//student.name="李四";//student.age=18;//正确做法:student.setName("李四");student.setAge(18);System.out.println(student.getName());}
}

在上述的例子中name和age被修饰,只能在类中被访问,不能在其他类中被访问。

当在Test这个类通过修改name和age时可以看到代码是报错的。

应该通过定义和方法,提供对name和age的访问以及修改。

可以看到此时代码不会报错了。

这种方式实现了封装,能够确保name和age只能通过提供的方法进行访问和修改。

5.2 包 包的概念:

在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。

包命名规则:

只能包含数字、字母、下划线和“.”,但是不能用数字开头,不能是关键字。通常会用公司的域名的颠倒形式

例:com.bit.demo1

包的使用:

1.在Java源文件的第一行使用语句导入包其他包中的类。例如:

import java.util.Date; 

这个语句表示我们要使用 java.util 包下的Date类,后面就可直接使用该类

2.不在第一行用语句导入包中所需的类,在后面使用该类时这么写,此法较麻烦

java.util.Date date = new java.util.Date();

3.还可以导入一个类,让你想用什么类都无需额外写,只需导入这一个类就行s

import java.util.*

但是在这里更建议直接的指定要导入的类名. 否则还是容易出现冲突的情况.

4.使用 导入包中静态的方法和字段

例如:

import static java.lang.Math.*;

当导入了上述的方法,那么下面这句

double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));

就可以这么写:

double result = sqrt(pow(x, 2) + pow(y, 2));

可以看到静态导入的方式写起来更方便一些

如何创建一个包:

2. 在弹出的对话框中输入包名, 例如 com.bit.www

3. 在包中创建类, 右键包名 -> 新建 -> 类, 然后输入类名即可.

在创建好包之后,在包中创建的类中最上面会有一个语句来告诉你这个类属于哪个包

注意:在不同包中建相同名称的类是不冲突的,但在相同包下创建相同名称的类是冲突的。

常见的包:

1. java.lang:系统常用基础类(、),此包从JDK1.1后自动导入。

2. java.lang.:java 反射编程包;

3. :进行网络编程开发包。

4. java.sql:进行数据库开发的支持包。

5. java.util:是java提供的工具程序包。(集合类等) 非常重要

6. java.io:I/O编程开发包

6.成员

修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。

6.修饰成员变量

【静态成员变量特性】

1. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中

张三,李四,王五是一个班的,他们上课一定在同一教室上课,那么上课教室就是张三,李四,王五这个几个对像共享的

class Student {private String name;private int age;//private String classRoom;public static String classRoom;public Student(String name, int age) {this.name = name;this.age = age;this.classRoom=classRoom;}public String getClassRoom() {return classRoom;}public void setClassRoom(String classRoom) {this.classRoom = classRoom;}public void sleep(){System.out.println(this.name+"正在睡觉");}
}
public class Test {public static void main(String[] args) {Student student1=new Student("张三",10);student1.setClassRoom("3-108");Student student2=new Student("李四",10);student2.setClassRoom("3-108");Student student3=new Student("王五",10);student2.setClassRoom("3-108");}
}

变量被修饰时:

变量被修饰时:

2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问,因为修饰的变量不属于某个具体的对象,虽然可以通过对象访问但这么做想想其实不合理

class Student {public static String name;public static int age;//private String classRoom;public Student(String name, int age) {this.name = name;this.age = age;//this.classRoom=classRoom;}public void sleep(){System.out.println(name+"正在睡觉");}
}
public class Test {public static void main(String[] args) {Student student=new Student("张三",10);
//        方法一:(不推荐)student.name="李四";student.age=18;student.sleep();//        方法二:(推荐)Student.name="王五";Student.age=19;student.sleep();}
}

运行结果:

3. 类变量存储在JVM方法区当中

4. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)

6.修饰成员方法

Java中,被修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的。

【静态方法特性】

1. 不属于某个具体的对象,是类方法

2. 可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者

class Student {public static String name;public static int age;public Student(String name, int age) {this.name = name;this.age = age;}public void eat(){System.out.println(this.name+"正在吃饭");}public static void sleep(){System.out.println(name+"正在睡觉");}
}
public class Test {public static void main(String[] args) {Student student=new Student("张三",10);//通过对象调用student.sleep();//通过类名.静态方法名(...)调用Student.sleep();}
}

3. 不能在静态方法中访问任何非静态成员变量

4. 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用

6.成员变量初始化

静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。

1. 就地初始化

就地初始化指的是:在定义时直接给出初始值

public class Student{private String name="张三";private String gender="男";private int age=10;private double score=100.0;private static String classRoom = "Bit306";
// ...
}

2. 静态代码块初始化

那什么是代码块呢?继续往后看。

7. 代码块

使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:

普通代码块:定义在方法中的代码块构造代码块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。静态代码块:使用定义的代码块称为静态代码块。一般用于初始化静态成员变量。同步代码块(本文不涉及)

class TestStatic {public static int staticNum = 100;public int data1 = 10;{//构造代码块 || 实例代码块System.out.println("实例代码块被执行了....");data1 = 1000;//一般情况下  用来初始化 非静态的数据成员}static {//静态代码块:初始化静态成员变量。System.out.println("静态代码块被执行了....");staticNum = 9999;}static {staticNum = 91999;}public TestStatic() {System.out.println("执行构造方法.....");}public static void main(String[] args) {TestStatic testStatic1 = new TestStatic();System.out.println(testStatic1.data1);System.out.println(TestStatic.staticNum);System.out.println("--------------------");TestStatic testStatic2 = new TestStatic();{//普通代码块}}
}

运行结果:

运行结果我们可以看出:1.执行顺序:静态代码块>实例代码块>构造方法

2静态代码块不管生成多少个对象,其只会执行一次

注意事项:

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了