【Java 基础】类和对象(构造&this&封装&static&代码块)
island1314 2024-09-03 14:05:03 阅读 76
✨ 风起于青萍之末,浪成于微澜之间 🌏
📃个人主页:island1314
🔥个人专栏:java学习
⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞
目录
🚀引言
1. 类定义和使用及实例化
1.1 创建类的语法
1.2 创建具体的对象(实例化)
1.3 范例🌰
2. 构造方法
2.1 定义构造方法
2.2 构造方法重载
3. this 关键字
3.1 this关键字调用当前对象的成员变量
3.2 this关键字调用当前对象的方法
3.3 注意事项
4. 封装
4.1 访问限定符
4.2 封装扩展之包
🥝包的概念
🥑导入包中的类
🍉自定义包
5. static 关键字
5.1 static修饰成员变量
5.2 static修饰成员方法
5.3 static成员变量初始化
6. 代码块
6.1 普通代码块
6.2 构造代码块
6.3 静态代码块
7. 扩展知识
7.1 匿名对象
7.2 toString方法
📖总结
🚀引言
在Java中一切皆对象,一切都围绕对象进行,找对象、建对象,用对象等。
类:把具有相同属性和行为的一类对象抽象为类。类是抽象概念,如人类、犬类等,无法具体到每个实体。
对象:某个类的一个实体,当有了对象后,这些属性便有了属性值,行为也就有了相应的意义。
类是描述某一对象的统称,对象是这个类的一个实例而已。有类之后就能根据这个类来产生具体的对象。其中类对象所具备的共同属性和行为(方法)都在类中定义。比如:描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成后计算机就可以识别了。
1. 类定义和使用及实例化
1.1 创建类的语法
<code>class ClassName {
成员变量/ 实例变量;
成员方法;
}
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
💢类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类的成员变量。方法主要说明类具有哪些功能,称为类的成员方法。
1.2 创建具体的对象(实例化)
用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象
类名称 引用名称 = new 类名称()
Person per = new Person();
这个对象的引用 对象(在堆中储存)
(相当于给对象起了个名字)(所有类的对象都是引用数据类型)
注意事项:
new 关键字用于创建一个对象的实例.使用: . 来访问对象中的属性和方法.同一个类可以创建对个实例.
1.3 范例🌰
下面创建一个Animal 类的对象:
class Animal {
String name;
int age;
void eat(String name) {
System.out.println(name + "正在吃");
}
void show() {
System.out.println("name:" + name + ",age:" + age);
}
}
public class Test {
public static void main(String[] args) {
Animal dog = new Animal();
dog.show();
dog.name = "小黄";
dog.age = 18;
dog.show();
}
}
💢💢输出如下:
注:
在Java中一个源文件(*.java)只可以存在一个主类(public class),而且public修饰的类必须要和文件名相同,main方法所在的类一般要使用public修饰类的命名规则:使用有意义的大驼峰单词命名法,每个单词的首字母都要大写类中定义的成员变量都有默认值关于引用数据类型的特殊值 null:null在Java中表示“空引用”,即只有名字,没有任何对内存中的地址,如果直接使用值为null的引用,去操作(使用.操作符)任何属性或者方法(成员变量、成员方法),都会报错。 如:空指针异常
2. 构造方法
2.1 定义构造方法
构造方法(也称为构造器)是一个特殊的成员方法,使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作。在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
new 执行过程
为对象分配内存空间(空间大小由该类中成员变量的属性决定)调用对象的构造方法为对象成员变量赋值(当构造方法调用结束后,该对象初始化完成)
在使用时需要注意以下几点:
方法名称必须与类名相同没有返回值类型,设置为void也不行创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数。若类中定义了构造方法,则默认的无参构造将不再生成。构造方法可以重载,规则和普通方法的重载一致 (用户根据自己的需求提供不同参数的构造方法)
注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。
下面定义了一个Animal 的一个无参构造:
<code>class Animal {
String name;
int age;
public Animal(){
System.out.println("无参构造");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
}
}
2.2 构造方法重载
构造方法是为了类中的成员变量赋值的,此时的重载只可能是参数的个数不同。
class Animal {
String name;
int age;
public Animal(){
System.out.println("无参构造");
}
public Animal(String s,int x){
name = s;
age = x;
System.out.println("带两个参数的构造");
}
}
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal();
Animal animal2 = new Animal("蛙",19);
}
}
注:不能用一个实例化对象去调用它的构造方法?
原因:构造方法就是去产生对象,如果用构造方法产生的对象去调用产生它的构造方法,就相当于自己又在自己的构造方法(这样就变成了我生我自己)
3. this 关键字
3.1 this关键字调用当前对象的成员变量
在了解了构造之后,我们先来看一个例子:
class Animal {
String name;
int age;
public Animal(String name,int age){
name = name;
age = age;
System.out.println("带两个参数的构造");
}
void show() {
System.out.println("name:" + name + ",age:" + age);
}
}
public class Test {
public static void main(String[] args) {
Animal animal2 = new Animal("蛙",19);
animal2.show();
}
}
输出如下:
疑问:为什么我们已经通过构造方法给成员变量初始化了,但输出结果仍是默认值呢?
原因:形参名称与成员变量名称相同。程序设计理念:就近匹配原则,编译器会找最近的相同名称的变量在哪
那么我们该如何解决上面这个问题了,就需要用到 this 关键字
修改如下:
<code>public Animal(String name,int age){
this.name = name;
this.age = age;
System.out.println("带两个参数的构造");
}
3.2 this关键字调用当前对象的方法
① 调用普通的成员方法
<code>class Animal {
String name;
int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
System.out.println("带两个参数的构造");
}
void show() {
System.out.println("name:" + name + ",age:" + age);
}
//show()方法是成员方法,必须通过对象调用
//this表示对象的引用,调用成员方法时不写,编译时也会自动加上
void func() {
show(); // 相当于 this.show()
System.out.println("成员方法调用");
}
}
💢 这个我们后面可以用在特殊场景下当成员方法被private修饰,我们就可以在类中新写一个函数,来调用。
② 构造方法的相互调用
若不同参数的构造方法之间出现了重复的调用,可以使用 this(参数)调用其他的构造方法。
class Animal {
String name;
int age;
public Animal(){
System.out.println("无参构造");
}
public Animal(String name){
this();
this.name = name;
}
public Animal(String name,int age){
/*this.name = name;
this.age = age;*/
this(name);
System.out.println("带两个参数的构造");
}
}
3.3 注意事项
① this调用其他的构造方法必须放在当前构造方法的首行
② this调用构造方法不能成环(避免构造方法就死循环了)
③ this关键字表示当前对象的引用
(当前是通过哪个对象调用的属性或者方法,this就指代此对象)
<code>class Animal {
String name;
int age;
void fun(){
System.out.println(this);
}
}
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal();
System.out.println(animal1);
animal1.fun();
}
}
输出如下:
注:前面的Note.Test1 是该文件所在的文件夹。(也就是下面将会提到包的概念)
4. 封装
面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?我们该文中主要讲到的就是 封装 这一概念。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互,具有保护性和易用性。
4.1 访问限定符
作用:访问权限用来控制方法或者字段能否直接在类外使用
【Java提供的四个访问限定符号如下】
权限修饰符:在Java中,权限修饰符指的是所修饰的属性、方法或者类可见的范围有多大。
范围 | protected | default | protected | public |
同一包中的同一类 | ✔️ | ✔️ | ✔️ | ✔️ |
同一包中的不同类 | ✔️ | ✔️ | ✔️ | |
不同包中的子类 | ✔️ | ✔️ | ||
不同包中的非子类 | ✔️ |
【说明】
protected主要是用在继承中,继承部分详细介绍default权限指:什么都不写时的默认权限访问权限除了可以限定类中成员的可见性,也可以控制类的可见性
封装有很多表现形式,private实现属性和方法的封装只是其中一种。
注:private 关键字不能直接修饰一个类(外部类)如:private class A
💢原因:定义类是为了产生对象,让外部使用的。若用 private 关键字封装此类,则外部根本不知道此类的存在,更不用提使用对象了,就和我们的目的产生矛盾。
4.2 封装扩展之包
🥝包的概念
为了更好的管理类,把多个类收集在一起成为一组,称为软件包。
比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件下,也可以对某个文件夹下的音乐进行更详细的分类。
🍎🍎在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
🥑导入包中的类
使用 import语句导入包.可以使用import static导入包中静态的方法和字段
<code>/*import java.util.*; 表示只要是 util下的所有类都可以适配
,但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况*/
import java.util.Arrays;
import java.util.Date; // 导入包中的 Date类,使用时: Date date = new Date();
// import static 能够导入一些静态方法,
//如下:
import static java.lang.Math.*;
public class Test {
public static void main(String[] args) {
double x = 30;
double y = 40;
// 静态导入的方式写起来更方便一些.
// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
double result = sqrt(pow(x, 2) + pow(y, 2));
System.out.println(result);
}
}
🍐🍐注:import 和 C++ 的 #include 差别很大,C++ 必须 #include 来引入其他文件内容,但是 Java 不需要,import 只是为了写代码的时候更方便,import 更类似于 C++ 的 namespace 和 using
🍉自定义包
基本规则
在文件的最上方加上一个 package 语句指定该代码在哪个包中.包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.zxj.demo1 ).包名要和代码路径相匹配. 例如创建 com.zxj.demo1 的包, 那么会存在一个对应的路径 com/zxj/demo1 来存储代码如果一个类没有 package 语句, 则该类被放到一个默认包中.
常见的包
java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。 java.lang.reflect:java 反射编程包; java.net:进行网络编程开发包。 java.sql:进行数据库开发的支持包。 java.util:是java提供的工具程序包。(集合类等) 非常重要 java.io:I/O编程开发包。
5. static 关键字
5.1 static修饰成员变量
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
【静态成员变量特性】
不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问类变量存储在方法区当中
生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
class Animal {
String name;
int age;
static String sex;
public Animal(){
}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
void show() {
System.out.println("name:" + name + ",age:" + age + ",sex:" + sex);
}
}
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("小黄",18);
Animal animal2 = new Animal();
animal1.show(); animal2.show();
animal1.sex = "wsz"; //通过对象访问
Animal.sex = "未知"; //直接类名访问
animal1.show(); animal2.show();
}
}
输出如下:
注意:
Animal.sex = null;
上面这样写并不会报空指针异常:static属性称为类属性,通过类名称直接访问,此时没有对象也能调用(包含该类的null引用)
不能在方法中定义一个static变量
🍅原因:在方法中定义的变量是局部变量,在栈中存储,而 static变量是在方法区中存储,若要在方法中定义一个static变量就会产生矛盾,因为一个变量不可能既在栈中存储,又在方法区中存储。
拓展知识:
若在类中定义了一个常量,通常情况下都会把static 和 final 共同使用,称为类的常量
比如:
<code>class P {
final int age = 18;//成员常量,在堆中存储,必须在定义时就赋值
static String school = "北大"//静态变量,在方法区中存储,所有 P 类的对象共享
}
(因为age属于成员常量,P 类中的所有对象都有age这个属性,且值都是18——>天然的共享概念,将它定义为static final,所有 P 类的对象共享这个属性,全局唯一。(既节省空间,有对应共享语义))
全局常量的命名规则:所有单词全部大写,多个单词使用下划线分隔
static final String UNIVERSITY = "剑桥";
5.2 static修饰成员方法
被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的
【静态方法特性】
不属于某个具体的对象,是类方法可以通过对象调用,也可以通过类名.静态方法名(…)方式调用,更推荐使用后者不能在静态方法中访问任何非静态成员变量静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用静态方法无法重写,不能用来实现多态
注:
成员方法能否访问静态变量和静态方法
🍍必须通过对象访问的方法去调用,不需要对象就可以访问的变量和方法,逻辑通过static方法只能调用静态变量和静态方法等,static家族的成员可以相互调用(都属于静态域)
5.3 static成员变量初始化
注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性
静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。
就地初始化
就地初始化指的是:在定义时直接给出初始值静态代码块初始化
那什么是代码块呢?继续往后看 😃 ~~
6. 代码块
使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块构造块静态块同步代码块(这个涉及到多线程部分,暂时不讲)
6.1 普通代码块
定义在方法中的代码块。
<code>public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
这种用法一般较少见
6.2 构造代码块
定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。注:构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行。
class Animal {
String name;
int age;
{
System.out.println("Animal类的构造代码块");
}
public Animal(){
System.out.println("Animal类的无参构造");
}
}
public class Test {
public static void main(String[] args) {
Animal a1 = new Animal();
Animal a2 = new Animal();
}
}
输出如下:
6.3 静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。注:无论产生多少对象,只会执行一次,且静态代码块优先于构造块执行。
<code>class Animal {
String name;
int age;
{
System.out.println("Animal类的构造代码块");
}
public Animal(){
System.out.println("Animal类的无参构造");
}
static {
System.out.println("Animal类的静态代码块");
}
}
public class Test {
public static void main(String[] args) {
Animal a1 = new Animal();
Animal a2 = new Animal();
}
}
输出如下:
注意事项:
① 主类中的静态代码块优先于主方法执行。(JVM要执行主方法,首先要加载主类,主类一加载,静态块就执行了)
<code>public class Test {
static {
System.out.println("主类的静态代码块");
}
public static void main(String[] args) {
System.out.println("进入主方法");
}
}
输出如下:
② 静态变量存在于方法区中,类定义时就会有初始值(在以下代码中,初始值为10),类此时在方法区中。但此时类只是定义了,还没被加载。当主方法中使用了该类时,就需要把该类从方法区加载到内存中。类加载后,静态代码块就被执行了(x = 10——> x = 100)
<code>class St{
static int x = 10;
static {
x = 100;
System.out.println("St类的静态代码块");
}
public St(){
System.out.println("St类的无参构造");
}
}
public class Test {
public static void main(String[] args) {
St st = new St();
System.out.println(st.x);
}
}
输出如下:
总结:
静态代码块不管生成多少个对象,其只会执行一次静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)实例代码块只有在创建对象时才会执行
7. 扩展知识
7.1 匿名对象
匿名只是表示没有名字的对象.
没有引用的对象称为匿名对象匿名对象只能在创建对象时使用如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象
new出来的对象,没有引用指向,使用一次后就被JVM销毁。常用于测试类中的某些功能。 如 :new Person();
代码示例:
<code>class Person {
private String name;
private int age;
public Person(String name,int age) {
this.age = age;
this.name = name;
}
public void show() {
System.out.println("name:"+name+" " + "age:"+age);
}
}
public class Main {
public static void main(String[] args) {
new Person("cc",19).show();//通过匿名对象调用方法
}
}
// 执行结果
name:cc age:19
7.2 toString方法
当一个引用类型的变量调用println函数打印时,默认输出的都是引用类型的地址。(不是真正的内存地址,Java中程序员是无法知道任何确认的内存地址)
正常情况下:
class St{
int x;
public St(int x){
this.x = x;
}
}
public class Test {
public static void main(String[] args) {
System.out.println(new St(12));
System.out.println(new St(14));
}
}
在类中构造一个toString()方法,对象默认调用此方法进行打印。
注意事项:
toString 方法会在 println 的时候被自动调用.将对象转成字符串这样的操作我们称为 序列化.toString 是 Object 类提供的方法, 我们自己创建的 Person 类默认继承自 Object 类, 可以重写 toString 方法实现我们自己版本的转换字符串方法. (关于继承和重写这样的概念, 我们后面会重点介绍)@Override 在 Java 中称为 "注解", 此处的 @Override 表示下面实现的 toString 方法是重写了父类的方法. 关于注解后面的课程会详细介绍.IDEA快速生成Object的toString方法快捷键:alt+f12(insert)
📖总结
一个类可以产生无数的对象,类就是模板,对象就是具体的实例。类中定义的属性,大概分为几类:类属性,对象属性。其中被static所修饰的数据属性称为类属性, static修饰的方法称为类方法,特点是不依赖于对象,我们只需要通过类名就可以调用其属性或者方法。静态代码块优先实例代码块执行,实例代码块优先构造函数执行。this关键字代表的是当前对象的引用。并不是当前对象。
💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。