首页 > 编程语言 >#Java-面向对象进阶-1

#Java-面向对象进阶-1

时间:2024-11-16 14:45:42浏览次数:3  
标签:调用 Java 进阶 子类 面向对象 父类 方法 public 变量

1.static静态属性

static是Java中的一个修饰符,可用来修饰成员变量、成员方法

a. 静态变量

static修饰的成员变量称为静态变量

  • 静态变量被该类的所有成员共享
  • 调用方式:
    • 类名调用(推荐)
    • 对象名调用

例:创建方法

//在创建的类中:
public static String name;

调用:假设类为:Student

//类名调用:
Student.setName("lsh");
Student s1 = new Student();
Student s2 = new Student();
//对象名调用
s1.getName();
s2.getName();

这里的s1s2所获得的名字都是lsh

存储原理:
在堆内存中有一个静态存储位置(静态区)用来存储用static修饰的变量

  • 静态变量的加载是和类同时进行的,优于对象
  • 其他成员变量是在对象创建之后才被加载

当创建一个对象之后,这个对象在堆内存中可以找到静态区和其中的静态变量,随后把地址返回给main方法中的变量。这样就可以通过对象访问静态变量了。

值得注意的是:引用类型的变量在会自动初始化为null0


b.静态方法

静态方法一般在测试类和工具类中使用,在javabean不常使用

静态方法示例:

public static void main(String[] args)

主要作用就是,把方法封装在一个特定的类中,使用这个类名调用其中的方法


我们来回顾一下不同的类:

  • Javabean类:用来描述一类事物的类。比如Student,Teacher,Dog,Cat

  • 测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口

  • 工具类:不是用来描述一类事物的,而是帮我们做一些事情的类。

详细介绍工具类的特点:

  • 没有成员变量
  • 私有化构造方法:不让外界创建它的对象,没有实际的意义
  • 方法定义为静态:可以使用类名调用
  • 类名有意义(见名知意)

给出调用的例子:(部分代码)

int[] arr1 = {1, 2, 3, 4, 5};
//调用类中的遍历方法
String str = ArrayUtil.printArr(arr1);//类名调用
System.out.println(str);

double[] arr2 = {1.5, 3.7, 4.9, 5.8, 6.6};
//调用类中的求平均值方法
double avg = ArrayUtil.getAverage(arr2);//类名调用
System.out.println(avg);

案例:(求学生中年龄最大值)

//工具类:
class Math {
    private Math() {};
    //年龄的最大值
    static int Max(ArrayList<Student1> list){
        int max = list.get(0).getAge();
        for (int i = 1; i < list.size(); i++) {
            max = max >= list.get(i).getAge() ? max :list.get(i).getAge();
        }
        return max;
    }
}
//Javabean类
//略(就是一个学生类,包含名字,年龄,性别)

//测试类:
public class b_11_11_2 {
    public static void main(String[] args) {
        ArrayList<Student1> list = new ArrayList<>();

        Student1 s1 = new Student1("lsh", 20, "man");
        Student1 s2 = new Student1("ls", 21, "man");
        Student1 s3 = new Student1("lh", 23, "women");

        list.add(s1);
        list.add(s2);
        list.add(s3);

        int max = Math.Max(list);
        System.out.println(max);
    }
}

2.static注意事项

  • 静态方法中没有this关键字
  • 静态方法只能访问静态变量和静态方法
  • 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法

2.1 静态方法中没有this关键字

我们前面已经提到,在非静态的方法种实际是有this关键字的,例如:

//假设我创建了学生类Student,成员变量有name,age
public int Math() {
	System.out.println(name + "的年龄是:" + age)
}

当我在main方法中给对象的成员变量赋值之后,就可以正常输出
是因为:在这个方法中有this,它的值是调用这个方法的对象的地址
例如:

//在main方法中
s1.Math();
//
public int Math(Student this) {
	System.out.println(this.name + "的年龄是:" + this.age)
}

实际上this就代表了s1


但是在静态方法中没有this关键字

静态方法可以被对象调用,但是和调用它的对象没有什么关系,所以在设计的时候就没有this关键字

2.2 静态方法只能访问静态变量和方法

因为静态方法没有关键字,所以无法访问非静态的变量和方法
例:

//假设我创建了学生类Student,成员变量有name,age
public static void math() {
	System.out.println(name);
}

上述代码是会报错的,同样也不能访问非静态的方法

//假设我创建了学生类Student,成员变量有name,age
public static void math() {
	System.out.println(name);
	show();//假设是我创建的非静态方法
}

当非静态的方法调用其他方法时:

public void math() {
	this.show();//假设是我创建的非静态方法
}

实际上是有this.show();所以可以访问其他方法
但是在静态方法中没有this关键字,所以就不能访问

2.3 非静态方法的访问

非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法

跟上面的解释一样:

  • 因为静态的方法中有this关键字
  • 同时静态的变量和方法可以被对象调用,所以就可以访问

3. 重新认识main方法

给出下面的代码:

public class HelloWorld {
	public static void main(String[] args) {
		System.out.println("HelloWorld");
	}
}
  • public: 被JVM(Java虚拟机)调用,访问权限足够大
  • static :被JVM调用,不用创建对象,直接类名访问, 因为main方法是静态的,所以测试类其他方法也需要是静态
  • void: 被JVM调用,不需要给JVM返回值
  • main: 一个通用的名称,虽然不是关键字,但是被JVM识别
  • String[] args: 以前用于接收键盘录入数据的,现在没用

4. 继承

继承是面向对象的三大特征之一,可以让类和类之间产生子父的关系
为什么使用继承:

  • 类和类之间,存在相同的内容并满足子类是父类的一种,可以使用继承来优化代码;例如:学生类和老师类,父类可以为“人”
  • 类和类之间没有联系时,不建议使用继承;例如:程序员和手机

继承的格式:

public class 子类 extends 父类 {}

我们同样以学生和老师类为例:

  • 学生:成员变量:姓名、性别、年龄;成员方法:吃饭、睡觉、学习、打豆豆
  • 老师:成员变量:姓名、性别、年龄;成员方法:吃饭、睡觉、教书

在这两个类中有很多重复的部分,例如:姓名、性别、年龄;行为:吃饭、睡觉

为了优化代码,我们可以把上述的内容封装在另一个类中,比如:person,作为父类,子类可以继承这些内容,并且子类可以有自己独特的成员变量和方法

这就是继承

4.1 继承的特点

Java只支持单继承,不支持多继承,但支持多层继承

  • 单继承:一个子类只能继承一个父类
  • 多层继承:子类A继承父类B,父类B可以继承父类C

在Java中没有爷爷等的说法,以上面为例:父类B称为A的直接父类,父类C称为A的间接父类

Java支持多层继承,所以在Java设计的时候,有一个最大的父类object,所有的类都继承于这个类。
例如:

public class c_11_12 {
    public static void main(String[] args) {
        student s1 = new student();
        s1.equals('a');
    }
}
class student{}

在这里插入图片描述
如上图所示,在student中我并没有写任何的方法,但是仍然可以调用一些方法,这就是继承于object的方法

示例来自黑马程序员

在这里插入图片描述


具体代码示例:
写出以下类:并使用继承优化代码

  • 狸花猫:吃饭、喝水、抓老鼠、有一定危险
  • 布偶:吃饭、喝水、抓老鼠、可爱
  • 哈士奇:吃饭、喝水、看家、拆家
public static void main(String[] args) {
        Ragdoll ra = new Ragdoll();
        ra.Cue();
        ra.CatchMouse();
        ra.Drink();
        ra.Eat();
        System.out.println("------------");
        Hasky ha = new Hasky();
        ha.BreakHome();
} //测试类
class Animal{
    public void Drink(){
        System.out.println("喝水");
    }
    public void Eat(){
        System.out.println("吃饭");
    }
} //动物类
class Cat extends Animal{
    public void CatchMouse(){
        System.out.println("抓老鼠");
    }
}//猫类
class Dog extends Animal{
    public void Lookhome() {
        System.out.println("看家");
    }
}//狗类
class lihua extends Cat{
    public void Danger() {
        System.out.println("危险");
    }
}//狸花猫
class Ragdoll extends Cat{
    public void Cue() {
        System.out.println("可爱");
    }
}//布偶
class Hasky extends Dog{
    public void BreakHome() {
        System.out.println("拆家");
    }
}//哈士奇

在这里插入图片描述

  • 当我们写代码的时候,可以采用先画结构图,再写的方法
  • 写的时候先从最高的父类开始写,依次往下

需要我们注意的是:
当父类中的方法为私有private时,子类不能继承


4.2 父类中成员私有和非私有

父类中的哪些成员是子类可以继承的呢:

  • 构造方法:不管是不是非私有,都不可以继承
  • 成员变量:都可以继承,但是父类中私有的成员变量不能直接调用
  • 成员方法:非私有可以继承,但是私有不可以继承
a.构造方法

这个很好理解,如果可以继承父类的构造方法,就不符合Java的语法规范了

  • 因为父类的名字和子类不一样,但是构造方法要求必须和类名一致
  • 如果可以继承就会报错

b.成员变量

不管是不是私有的成员变量,在创建子类的对象的时候,都会在堆内存中开辟一个包含父类中成员变量的方法。
在访问的时候会先访问子类中已有的成员变量,之后再访问从父类中继承的成员变量。

值得注意的是:虽然父类中私有的成员变量可以继承,但是不能直接访问

我们来看内存图:来自黑马程序员
在这里插入图片描述
可以看到,上面父类的成员变量是再子类的对象中的:

private String name;
private int age;
//子类中的
String game;

但是不能直接进行访问和修改,如果要访问要用到父类中的getter和setter方法

同时,我们可以看到,在方法区中,当加载子类的时候,同时也加载了父类。当然object作为最大的父类,也是会被加载


c.成员方法

前面说到:非私有的方法可以被继承,其实准确的来说:
虚方法表中的方法可以被继承
而非私有的成员方法在虚方法表中

虚方法表:

  • private方法
  • static方法
  • final方法

在继承的时候虚方法表中的方法会根据子类而改变:
在这里插入图片描述
在虚方法表中会添加上子类自己的虚方法,这样在调用父类中的方法时,就可以直接在虚方法表中进行查找,而不需要一层一层向父类查找

  • 在虚方法表外的方法还是要一层一层的向父类查找,效率较低
  • object中有5个方法在虚方法表中

4.3 继承中的就近原则

当局部变量、成员变量、父类中的成员变量重名了,我们在调用的时候该使用哪一个呢?
看代码:

public class Fu {
	String name = "Fu";
}//父类
public class Zi extends Fu{
	String name = "Zi";
	public void ziShow(){
		String name = "ziShow";
		System.out.println(name);
	}
}//子类

其遵循“就近原则”:

  • 先访问离自己最近的局部变量
  • 如果没有局部变量,就访问本类中的成员变量
  • 如果子类中没有这个名字的成员变量,就访问父类中的成员变量
  • 如果都没有就报错

同时前面我们介绍了this关键字,这里再介绍super关键字
super关键字使用方法和this相同,但是super指的是访问当前类的父类中的成员变量
例:在上面的代码中:

System.out.println(super.name);

输出的结果就为FU

  • super只能调用最近的父类,不能调用多个
  • 同样使用this.name,结果就为:ZI

同样的在父类和子类中有重名的方法的时候,也和上面的一样:

  • 就近原则:谁离得更近就调用谁
  • this:调用本类的成员方法
  • super:调用最近父类的成员方法

4.4 方法重写

当父类的方法不能满足子类现在的需求时,需要进行方法重写

书写格式:
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法,是重写的方法。


@Override重写注解

  1. @Override是放在重写后的方法上,校验子类重写时语法是否正确。

  2. 加上注解后如果有红色波浪线,表示语法错误。

  3. 建议重写方法都加@Override注解,代码安全,优雅

示例:

class FU{
	public void Live() {
		System.out.println("正在努力的生存");
	}
}
class ZI{
	@Override
	public void Live() {
		System.out.println("傻傻的享受");
	}
}

更进一步来说,实际上方法的重写是对虚方法表中的方法进行了覆盖
例如:三个类:A、B、C,A是B的子类,B是C的子类
当在B中重写从C继承过来的方法(假设为方法M),在B的虚方法表中就把方法M改为了B中的。如果A也进行M的重写,在A的虚方法表中方法M就变为了A中的。
图例:
在这里插入图片描述


方法重写注意事项和要求:

  1. 重写方法的名称、形参列表必须与父类中的一致。

  2. 子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写 < protected < public)

  3. 子类重写父类方法时,返回值类型子类必须小于等于父类

  4. 建议: 重写的方法尽量和父类保持一致

  5. 只有被添加到虚方法表中的方法才能被重写

4.5 父类构造方法的调用

子类不会继承父类的构造方法,但是子类中的所有构造方法会默认先访问父类中的无参构造,再执行自己


为什么:

  • 子类在初始化的时候,有可能会使用到父类中的数据。如果父类没有完成初始化,子类将无法使用父类的数据。

  • 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。

示例:

class Zi{
	//子类中空参构造
	public Zi() {
		super();//即使不写也会有
	}
	//有参构造
	public Zi(String name) {
		super(name);//当name是继承自父类的时候需要手动加上
		}
	}
}

注意事项:

  • 子类不能继承父类的构造方法,但是可以通过super调用

  • 任何子类构造方法的第一行,有一个默认的super(),这是为了确保在实例化子类对象时,父类也能被正确的初始化

  • 默认先访问父类中无参的构造方法,再执行自己。

  • 如果想要方法文父类有参构造,必须手动书写。


thissuper的总结:

  • this: 理解为一个局部变量,表示当前方法调用者的地址值;

  • super: 代表父类存储空间。

在这里插入图片描述

  • this 在访问构造方法的时候,访问的是本类的其他构造方法
  • 使用场景一般为:在无参构造是设置默认的初始值;
public class Student {
	String name;
	int age;
	String school;
	public Student () {
		//表示调用本类其他构造方法
		//细节:虚拟机就不会再添加super();
		this(name: null,age:0,school:"传智大学");
	}

	public Student(String name, int age, String school) {
		//super();
		this.name = name;
		this.age = age;
		this. school = school;
	}
}

在方法中使用this调用了其他的本类构造方法时,JVM(Java虚拟机)就不会在这个类中添加super()了,因为其他类中一定会有显式或者隐式的super()


标签:调用,Java,进阶,子类,面向对象,父类,方法,public,变量
From: https://blog.csdn.net/2302_80203877/article/details/143671534

相关文章

  • #Java-面向对象进阶-多态
    1.多态多态是面向对象三大特征之一,表示同类型的对象表现不同的形态表现形式:父类类型对象名称=子类对象;多态的前提:有继承关系有父类引用子类Fuf=newZi();有方法重写使用场景举例:当需要写一个注册的方法,但是这个方法要能实现不同对象的注册例如:老......
  • Java序列化与反序列化深度解析
    一、引言在Java开发中,序列化与反序列化是非常重要的概念和技术手段。它允许我们将对象转换为字节流以便于存储或传输,然后在需要的时候再将字节流还原为对象。这一机制在很多场景中都有着广泛的应用,例如数据持久化、分布式系统中的远程方法调用(RMI)、缓存等。本文将深入探讨......
  • 7.Java 注解和元注解(三种注解、四种元注解)
    一、注解概述注解也被称为元数据,用于修饰包、类、方法等数据信息和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息在JavaSE中,注解使用的目的比较简单,例如标记过时的功能,忽略警告等JavaEE中注解会充当更加重要的角色二、三种注......
  • JavaScript判断用户设备类型:PC端与移动端的区分方法
    在JavaScript中,可以通过检查用户代理字符串(UserAgentString)来判断用户设备类型,即访问网站的是PC端还是移动端设备。用户代理字符串是浏览器在发送HTTP请求时附带的一段信息,它包含了浏览器类型、版本、操作系统以及设备类型等信息。以下是一个简单的示例代码,用于判断用户......
  • 一文详解Java反射技术
    Java反射什么是Java反射以及引出反射的背景?Class类如何获取一个class的Class实例Class类的使用获取属性获取调用方法获取注解信息获取构造方法反射的应用什么是Java反射以及引出反射的背景?Java程序中的对象有两种类型,编译时类型和运行时类型,而很多时候编译......
  • Java反序列化-Commons Collections3利用链分析详解
    介绍CC3与CC1和CC6的主要区别在于,CC1和CC6依赖反射机制来执行Runtime.getRuntime().exec()等危险命令,而如果服务器将这些方法列入黑名单,这两种方式就会失效。相比之下,CC3通过类加载器动态加载恶意类来执行危险函数,绕过黑名单限制,从而达到命令执行的目的。公众号:T......
  • java笔试题
    请指出下面程序的运行结果(62)publicclassTest{publicstaticvoidmain(String[]args){System.out.println(test());}publicstaticinttest(){try{return2;}catch(Exceptione){return4;......
  • 前端必知必会-JavaScript if、else 和 else if
    文章目录JavaScriptif、else和elseif条件语句if语句else语句elseif语句总结JavaScriptif、else和elseif条件语句用于根据不同的条件执行不同的操作。条件语句编写代码时,您经常希望针对不同的决策执行不同的操作。您可以在代码中使用条件语句来执行......
  • 前端必知必会-JavaScript Switch 语句
    文章目录JavaScriptSwitch语句JavaScriptSwitch语句break关键字default关键字常见代码块switch详细信息严格比较总结JavaScriptSwitch语句switch语句用于根据不同的条件执行不同的操作。JavaScriptSwitch语句使用switch语句从多个代码块中选择一个......
  • java根据时区转换获取时间的方法
    方法一:publicstaticvoidmain(String[]args){//假设这是从MySQL获取的UTC时间字符串StringutcTimeStr="2024-09-30T16:00:00Z";try{//解析UTC时间字符串DateTimeparsedDateTime=DateUtil.parse(utcTimeStr......