首页 > 基础资料 博客日记
【Java 基础】类和对象(构造&this&封装&static&代码块)
2024-09-06 09:00:08基础资料围观116次
✨ 风起于青萍之末,浪成于微澜之间 🌏
🔥个人专栏:java学习
⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞
目录
🚀引言
在Java中一切皆对象,一切都围绕对象进行,找对象、建对象,用对象等。
类:把具有相同属性和行为的一类对象抽象为类。类是抽象概念,如人类、犬类等,无法具体到每个实体。
对象:某个类的一个实体,当有了对象后,这些属性便有了属性值,行为也就有了相应的意义。
类是描述某一对象的统称,对象是这个类的一个实例而已。有类之后就能根据这个类来产生具体的对象。其中类对象所具备的共同属性和行为(方法)都在类中定义。比如:描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成后计算机就可以识别了。
1. 类定义和使用及实例化
1.1 创建类的语法
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 的一个无参构造:
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 关键字
修改如下:
public Animal(String name,int age){
this.name = name;
this.age = age;
System.out.println("带两个参数的构造");
}
3.2 this关键字调用当前对象的方法
① 调用普通的成员方法
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就指代此对象)
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导入包中静态的方法和字段
/*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 共同使用,称为类的常量
比如:
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 普通代码块
定义在方法中的代码块。
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定义的代码块称为静态代码块。一般用于初始化静态成员变量。注:无论产生多少对象,只会执行一次,且静态代码块优先于构造块执行。
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要执行主方法,首先要加载主类,主类一加载,静态块就执行了)
public class Test {
static {
System.out.println("主类的静态代码块");
}
public static void main(String[] args) {
System.out.println("进入主方法");
}
}
输出如下:
② 静态变量存在于方法区中,类定义时就会有初始值(在以下代码中,初始值为10),类此时在方法区中。但此时类只是定义了,还没被加载。当主方法中使用了该类时,就需要把该类从方法区加载到内存中。类加载后,静态代码块就被执行了(x = 10——> x = 100)
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();
代码示例:
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 对象的打印
当一个引用类型的变量调用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关键字代表的是当前对象的引用。并不是当前对象。
💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
上一篇:C++入门基础
下一篇:java 实现文本转音频