当前位置: 首页 > news >正文

Java 类和对象详解(下)

个人主页:鲤鱼王打挺-CSDN博客

 

目录

💗前言:

💯一.static关键字

1. 为什么要使用static

2.  static 修饰成员变量:

 3.  static 修饰成员方法:

​编辑

4. 静态代码块 

 5.静态导入包

💯二.代码块

 1.实例代码块 

 2.静态代码块

3.普通代码块

💯三.继承

1.(过渡)toString方法

 2.为什么需要继承?

3.如何使用继承?

4.super关键字

5.子类 构造方法

6.代码块 

7.继承方式 

8.组合

9.protect 关键字 

💯四.小结


 

💗前言:

  上一篇文章(Java 类和对象详解(上 )-CSDN博客)中我们详细提到了类与对象的组成成分如下图,在明白什么是成员方法,什么是构造方法后,我们今天用不一样的方法来了解什么是静态以及类和对象中的其他组成部分!(无奖竞猜:大家可以找找下图中有什么错误)

💯一.static关键字

为什么要把static修饰符放到这么后面来讲呢?其实大家在学习Java时一开始就会接触static关键字,就是我们的main方法,而且大家在学校,老师可能在学习类的第一堂课就在提到它。

但是我这篇文章是起到给大家梳理的作用,所以我们一块一块的提及,static包括成员方法,成员变量以及代码块(重点是静态代码块,所以必须先知道什么是静态)等都会 使用,所以我们单独列出来一级。

废话不多说,我们先来看看什么是静态:

1. 为什么要使用static

当我们创建一个学生类,创建对象时,三个学生的班级是一样的,此时重复定义classroom变量不仅 麻烦,而且占用了内存空间所以当出现重复变量时,我们就不再让他重复开辟一段新的内存,此时就要用到static。

2.  static 修饰成员变量:

我们学习了局部变量和成员变量,成员变量也叫做实例变量,可以理解为"对象局部变量",而在成员变量前加上static时,称为"类变量",也叫做静态变量所以在定义类时,没有加上static的,都是成员变量。(前言中的图片中其中一个错误就是成员变量不能分成静态和非静态)

类变量可以理解为和类平起平坐,也可以说它的类型是一个类 类型而不属于对象。所以我们无需创建对象,也可以引用静态变量。 此时调试后发现,每个对象中的成员不包含classroom了。我们知道对象存储在堆中,而对象变量并不存储在栈中,而在方法区中。

 

我们可以直接用类名访问它(Student.classroom)  ,虽然我们可以再使用对象来引用它,但是无论你创建几个对象,它都是同一个classroom,不会开辟新的空间了。(这里并不建议用对象来访问它)

 3.  static 修饰成员方法:

 

如上图,此时报错:空指针异常。 当我们为ret方法加上static,使其变成一个静态方法。

可以发现,方法正常被调用,且可以直接用类名调用,这是因为static不依赖于任何对象!

 在1.中我们可以发现,调用类类型,小编是将它定义为public,那么如果我们让它变成我们常用的private,要怎么调用呢?

静态成员一般是通过 静态方法来访问的。

注意:(1)不能在静态方法中访问任何非静态成员变量 

           (2)静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用(因为已经不属于对象了)

           (3)普通成员方法是可以调用静态方法的 

此时我们再回过头看看main方法和普通方法,为什么要加static? 

因为这样我们就可以在main方法中不需要对象来调用方法了。是不是恍然大悟了呢,学习就是一个先完善再完美的过程。。。

注意:静态修饰后,它的生命周期随着类的加载而创建,随类的卸载而销毁 (后文会提到)。

4. 静态代码块 

静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性。 静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。 这就引出我们的代码块——>静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的

 5.静态导入包

import java.util.*;
public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int a = sc.nextInt();}
}

此时我们导入的包是java.util,而 * 是通配符,包含了Scanner类,所以这串代码可以正常运行。 

import java.util.Scanner;
import static java.lang.Math.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int a = sc.nextInt();double ret = Math.sqrt(Math.pow(a,2));double r = sqrt(pow(a,2));}
}

而静态导入后,导入所有静态方法,这样就不用带上类名了(不依赖对象),也算是小小的便利。 

💯二.代码块

使用 {} 定义的一段代码称为代码块,是类的一部分。

根据代码块定义的位置以及关键字,又可分为以下四种:

(1)普通代码块

(2)实例代码块

(3)静态代码块

(4)同步代码块 【小编暂时不提及】

 1.实例代码块 

构造块:定义在类中的代码块(不加修饰符), 也叫:实例代码块。构造代码块一般用于初始化实例成员变量。实例代码块只有在创建对象时才会执行。

{this.name = name;this.gender = gender;
}

 2.静态代码块

静态代码块一般用于初始化静态成员变量。

 static{classRoom = "夯大力123";System.out.println("静态代码块执行了");}

静态代码块也不能调用非静态的变量或方法,因为它不依赖于对象。

静态代码块是最先执行的(加载时就执行),且只执行一次,即使创建了多个对象。 

3.普通代码块

在方法中的代码块就是普通代码块,在代码块中的变量是代码块局部变量,代码块外无法调用。

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);}
}//x1 = 10   x2 = 100

一般来说,最先执行静态代码块,实例代码块次之,构造方法再执行。如果有多个静态代码块,那么按定义的顺序执行。

💯三.继承

1.(过渡)toString方法

当我们打印对象名的时候,我们会得出类名+@+数字的字符串 ,观察源码可以发现,println方法是调用了系统的toString方法。那么我们能不能调用自己的toStrting方法呢?

如下图: 这是什么原理呢?这就需要搬出我们的继承和多态。

public String toString(){return "name:"+name;}

 2.为什么需要继承?

 观察下方代码,Cat和Dog都有相同的成员变量,这样我们很难不联想到,能不能用Animal类来管理这两个类,这就是继承。

public  class Cat {public String name;public String color;public int age;public void say(){System.out.println(name+"喵喵");}}public class Dog {public String name;public String color;public int age;
}

继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性 的基础上进行扩展,增加新功能,这样产生新的类,称派生类。

继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。

3.如何使用继承?

 我们一般将需要继承的类如Animal称为父类/超类/基类,而Dog称为子类/派生类。继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。

继承格式如下:需要使用关键extends(注意不要漏掉s)

public  class Cat extends Animal {public String var;public void say(){System.out.println(name+"喵喵");}
}

子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承 

4.super关键字

当父类不存在与子类同名的成员时,子类直接访问父类成员。

如果父类与子类成员同名时,优先访问子类自己的。

朋友们此时如果使用this,会发现也是访问当前对象也就是子类成员。

而使用super关键字,就可以访问父类成员,成员方法也是如此。

class Animal {public String name;public String color;public int age;public int a = 222;public int b = 333;
}public  class Cat extends Animal {public int a = 111;public String var;public void test(){System.out.println("1:"+a);System.out.println("2:"+this.a);System.out.println("3:"+super.a);System.out.println("4:"+this.b);System.out.println("5:"+super.b);}
}

 

此时重写方法与父类方法同名,需要调用父类方法时,就需要用super方法。 

继承中也存在重载。

注意:

1. 只能在非静态方法中使用(this也是)

2. 在子类方法中,访问父类的成员变量和方法。super.+父类方法名()

3.为了提高代码的可读性,调用父类成员最好使用super关键字。

5.子类 构造方法

子类也会默认初始化无参构造方法,但当我们在构造子类构造器时会报错,这就是前文所说的"救急不救穷",系统不会再初始化无参构造器,所以我们要为父类添加构造器。可以记为:没有父哪有子?

注意:

1.在子类构造方法第一行默认有隐含的super()调用,即调用父类构造方法。

2.在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。  super(...)只能在子类构造方法中出现一次,并且不能和this同时出现。

小编发现这句有点误导,因为使用了super调用构造后,仍可以用this初始化对象,只是不能再用this调用方法了,因为this也要求在构造器的首行。如下图:

6.代码块 

在子类也能加入代码块,静态代码块是最先执行的。

 下图代码中打印的数字是执行顺序,可以发现是严格按照静态代码块先执行,父类实例优于子类实例,父类构造优于子类构造,由于实例代码块是对象被创建时执行,所以父类构造先于子类的实例代码块

class Animal {public String name;public String color;public int age;static{System.out.println("1 ");}{System.out.println("3");}public Animal(String name, int age){this.name = name;this.age = age;System.out.println("4");}}
public  class Cat extends Animal {public String var;static{System.out.println("2");
}{System.out.println("5");}public Cat(String name, int age){super(name, age);System.out.println("6");}

7.继承方式 

Java类有这几种继承方式,可以继承给子类,子类再继承给它的子类。

也可以父类继承给多个子类。

但是不允许多个父类的情况。 

 

当我们使用final关键字时,说明这个类无法被继承! 

8.组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。组合并没有涉及到特殊的语法 (诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。 小编的理解就是让一个类"继承"多个类的方式。

//汽车
public class Car {private Tire t;private Engine e;}
//轮胎
public class Engine {public int a;public int b;public int c;public int d;
}
//发动机
public class Tire {public int a;public int b;public int c;public int d;
}

 但是组合时,整体类不能自动获得局部类同样的接口,需要再创建类 对象,不像继承无需再创建

9.protect 关键字 

前文我们就提到protect,它的权限范围就是同一个包时,都可以访问;若是不同包,则只有父类的子类才可以访问成员。 

// extend01包中
public class B {
private int a;
protected int b;
public int c;
int d;
}
// extend01包中
// 同一个包中的子类
public class D extends B{
public void method(){
// super.a = 10; // 编译报错,父类private成员在相同包子类中不可见
super.b = 20; // 父类中protected成员在相同包子类中可以直接访问
super.c = 30; // 父类中public成员在相同包子类中可以直接访问
super.d = 40; // 父类中默认访问权限修饰的成员在相同包子类中可以直接访问
}
}
// extend02包中
// 不同包中的子类
public class C extends B {
public void method(){
// super.a = 10; // 编译报错,父类中private成员在不同包子类中不可见
super.b = 20; // 父类中protected修饰的成员在不同包子类中可以直接访问

💯四.小结

类与对象的成员包括什么?继承的细节在哪里体现?小编已经为大家制作了一篇文章供大家参考 

暂时就提到这里,小编还在对知识进行梳理!希望朋友们点点赞支持一下! 

 

 


http://www.mrgr.cn/news/54640.html

相关文章:

  • 提升SQL技能,掌握数据分析
  • 基于ElementPlus的table组件封装
  • 探索光耦:光耦——不间断电源(UPS)系统中的安全高效卫士
  • 全面解析:优化RAG效果的关键策略,非常详细收藏我这一篇就够了
  • 雷池WAF自动化实现安全运营实操案例终极篇
  • 在使用new Date()生成时间戳时,发现数据库中 的时间总是多出一秒钟。
  • Leetcode 3327. Check if DFS Strings Are Palindromes
  • 【动态规划】【路径问题】下降路经最小和、最小路径和、地下城游戏
  • 15. 三数之和 双指针经典题目
  • 【MySQL】to_date()日期转换
  • 模拟器芯片巨头 ADI 亚德诺半导体 Analog Devices 产品的应用介绍和物料推荐(六)
  • 【软件工程】过程和生命周期的建模
  • Android常用C++特性之std::bind
  • ArkTS 中Tabs 页签内引入页面的 onPageShow和onPageHide 没有执行,是什么原因?怎么解决?
  • python语言入门必须要学习的模块化编程案例游戏---画图案例(三)【源码大全】
  • 前端大佬都在用的useFetcher究竟有多强?
  • 医院信息化与智能化系统(3)
  • Atlas800昇腾服务器(型号:3000)—YOLO全系列NPU推理【跟踪】(八)
  • LeetCode Hot 100
  • 公交线路查询web管理系统||公交线路查询|基于SprinBoot+vue公交线路查询系统(源码+数据库+文档)
  • 第十七周:机器学习笔记
  • 音频/视频提取器:Python和moviepy实现
  • 【网安笔记】4种拒绝服务攻击
  • 【Android】JNI报错 non-zero capacity for nullptr pointer分析
  • 跨国SAP实施 - 美国 - 税法 - 咨询
  • YoloV10改进策略:注意力改进|DeBiFormer,可变形双级路由注意力|引入DeBiLevelRoutingAttention注意力模块(全网首发)