Java基础学习(六)

news/2025/1/11 22:39:20/文章来源:https://www.cnblogs.com/victoria6013/p/18666311

Java基础学习(六):面向对象

目录
  • Java基础学习(六):面向对象
    • 概念
    • 类的结构
    • 对象的创建与初始化
    • 内存分析
    • 封装
    • 继承
    • 多态
    • Instanceof 和 类型转换
    • Static 关键字
    • 抽象类
    • 接口
    • 内部类

本文为个人学习记录,内容学习自 狂神说Java


概念

  1. 面向过程 vs 面向对象
    • 面向过程
      • 步骤清晰简单,第一步做什么,第二步做什么,...
      • 适合处理一些较为简单的问题
    • 面向对象
      • 分类的思维模式,思考解决该问题需要哪些分类,然后对这些分类进行单独思考
      • 分类下的具体细节是面向过程的
      • 适合处理复杂的问题
  2. 什么是 面向对象
    • 面向对象编程(Object-Oriented Programming, OOP)
    • 面向对象编程的本质是:以类的形式组织代码,以对象的形式组织(封装)数据
    • 核心思想:抽象
    • 三大特性:封装、继承、多态

类的结构

类包含了 属性方法 两部分:

public class Student {// 属性String name;int age;// 方法public void study(){// 方法实现}
}

对象的创建与初始化

  • 使用 new 关键字创建对象 Student student = new Student();

  • 使用 new 关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化,以及对类中 构造器 的调用

  • 构造器 也称为构造方法,是在创建对象时必须调用的,有以下特点:

    • 必须和类的名字相同
    • 必须没有返回类型,也不能写 void
    • 构造方法用于初始化,包括 无参构造有参构造
    • 如果没有显式定义构造方法,会自动生成一个包含空语句的无参构造
    • 如果定义了有参构造但没有定义无参构造,是不会自动生成无参构造的,必须完全没有显式定义才会自动生成
    • 快捷键:Alt + Insert
    public class Person {String name;// 无参构造public Person(){this.name = "victoria";}// 有参构造public Person(String name){this.name = name;}
    }
    

内存分析

下面通过例子介绍一个基本程序的内存分配过程:

public class Application {public static void main(String[] args) {			// main方法作为程序入口Pet dog = new Pet();							// 创建对象dog.name = "a";dog.age = 3;dog.shout();}
}
class Pet {String name;int age;public void shout(){}
}

基本步骤:

  1. 在方法区中加载 Application 类,存储了 main 方法的具体实现,并将常量添加到常量池中;
  2. 在栈中创建一个栈帧用于执行 main 方法;
  3. 由于需要用到 Pet 类,因此在方法区中加载 Pet 类,存储了成员变量的元信息(包括名称、类型等)以及方法的具体实现;
  4. 执行 Pet dog = new Pet();时,先在栈中分配引用变量 dog 的空间,用于存储地址;
  5. 之后在堆中分配内存存储该对象的具体信息,name 初始化为 null,age 初始化为0;
  6. 通过引用变量找到堆中具体地址进行赋值,并根据方法表定位到 shout() 在方法区中的具体实现;
  7. main 方法执行完毕后栈帧被弹出,回收不再使用的内存。
图6-1

封装

  1. 公有(public)和私有(private)

    成员变量/方法通过 public 或者 private 修饰,表明该成员变量/方法能否被实例对象访问

    public class Application {public static void main(String[] args) {Student s1 = new Student();s1.name = "victoria";							// name是公有的,可访问s1.id = 1;										// id是私有的,不可访问,此处会报错}
    }
    class Student {public String name;private int id;
    }
    
  2. get / set

    • 为了防止外部随意改动,一般将类的成员变量设置成私有的,而为了能够读写成员变量,一般要提供公有的 get 方法和 set 方法

    • 快捷键:Alt + Insert

    public class Application {public static void main(String[] args) {Student s1 = new Student();String name = s1.getName();s1.setName("victoria");}
    }
    class Student {private String name;								// 成员变量设置成私有的public String getName(){							// get方法,用于获取私有成员变量的值return this.name;}public void setName(String name){					// set方法,用于设置私有成员变量的值this.name = name;}
    }
    

继承

  • 使用关键字 extends 表明继承关系:public class Student extends Person{} —— 表明 Student 类继承自 Person 类

  • Student 类继承自 Person 类,则 Student 类称为子类/派生类,Person 类称为父类/基类

  • 子类会继承父类的所有 public 和 protected 的属性和方法

  • Java 中所有的类默认继承自 Object 类

  • Java 中类只有单继承,没有多继承(接口可以多继承):一个父类可以有多个子类,但一个子类只能有一个父类

  • 访问修饰符:public、protected、private

    修饰符 同类 同包 跨包子类 跨包其他类
    public
    protected ×
    default(不带修饰符时) × ×
    private × × ×
  • thissuper

    this 指代当前类,super 指代父类,通过 this.属性/this.方法名() 访问当前类的属性/方法,通过 super.属性/super.方法名() 访问父类的属性/方法

    public class Application {public static void main(String[] args) {Student student = new Student();student.test();}
    }
    class Person {protected String name = "a";						// 父类中的成员变量name初始化为"a"
    }
    class Student extends Person{private String name = "b";							// 子类中的成员变量name初始化为"b"public void test(){System.out.println(name);						// 由于重写的存在,访问的一定是当前类的属性,输出为"b"System.out.println(this.name);					// 使用this访问当前类的属性,输出为"b"System.out.println(super.name);					// 使用super访问父类的属性,输出为"a"}
    }
    
  • 构造方法的执行:执行子类构造方法时默认调用了父类的无参构造

    public class Application {public static void main(String[] args) {Student student = new Student();				// 创建子类实例}
    }
    class Person {public Person(){									// 父类构造方法System.out.println("执行父类构造方法");}
    }
    class Student extends Person{public Student(){									// 子类构造方法System.out.println("执行子类构造方法");}
    }
    ===============================================================================
    输出结果:
    执行父类构造方法
    执行子类构造方法
    

    本质是在执行子类的构造方法时,第一行默认有一句代码 super(); ,如果显式给定该代码也必须放在构造方法的第一行

    如果需要调用父类的有参构造,需要显式写出:

    class Person {public Person(String name){							// 父类为有参构造System.out.println("执行父类构造方法");}
    }
    class Student extends Person{public Student(){super("victoria");								// 显式给定父类有参构造的执行System.out.println("执行子类构造方法");}
    }
    
  • 方法的重写

    • 需要有继承关系,子类重写父类的方法

    • 方法名、参数列表必须相同

    • 修饰符:范围可以扩大但不能缩小,修饰符范围:public > protected > default > private,比如父类是 protected,那么子类可以是 protected 或者 public

    • 抛出的异常:范围可以被缩小但不能扩大

    • 快捷键:Alt + Insert

    • 方法的重写只和非静态方法有关,也即:子类可以重写父类的非静态方法,无法重写静态方法,静态方法就算有相同的方法名和参数列表也不会被视为重写

      • A 是 B 的子类,A 和 B 有方法名和参数列表相同的静态方法:不会发生重写

        public class Application {public static void main(String[] args) {A a = new A();a.test();				// 使用实例对象调用静态方法,不规范但也不会报错,编译时会自动转换成 A.test();B b = new A();b.test();				// 使用实例对象调用静态方法,不规范但也不会报错,编译时会自动转换成 B.test();}
        }
        class A extends B{public static void test(){System.out.println("A=>test()");}
        }
        class B {public static void test(){System.out.println("B=>test()");}
        }
        ==================================================================================================
        输出结果:
        A=>test()
        B=>test()
        
      • A 是 B 的子类,A 和 B 有方法名和参数列表相同的非静态方法:会发生重写

        public class Application {public static void main(String[] args) {A a = new A();a.test();B b = new A();			// 多态:父类引用可以指向子类对象b.test();				// 由于发生了方法的重写,输出结果为 A=>test()}
        }
        class A extends B{public void test(){System.out.println("A=>test()");}
        }
        class B {public void test(){System.out.println("B=>test()");}
        }
        ==================================================================================================
        输出结果:
        A=>test()
        A=>test()
        
      • A 是 B 的子类,A 和 B 有方法名和参数列表相同的方法,但一个是静态一个是非静态:直接报错


多态

  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多

  • 父类的引用可以指向子类对象

    public class Application {public static void main(String[] args) {Student s1 = new Student();Person s2 = new Student();						// 父类的引用变量指向了子类对象Object s3 = new Student();						// 父类的父类的引用变量指向了子类对象}
    }
    class Person {}
    class Student extends Person {}
    

    需要注意两点区别:

    1. 等式左边决定:上面的 s2/s3 本质上还是 Person/Object 类的引用变量,它们只能调用父类本身存在的方法
    2. 等式右边决定:如果 s2/s3 调用的方法经过了 Student 类的重写,则具体执行的是 Student 类中的方法;若没有重写,则执行的还是 Person/Object 类本身的方法

Instanceof 和 类型转换

  • Instanceof :用于判断左侧引用类型变量指向的对象是否为右侧的类或其子类的对象,如果左侧引用类型和右侧类型完全无关则会直接编译报错(编译通不通过取决于引用类型,返回值为true/false取决于具体指向的对象类型)

    public class Application {public static void main(String[] args) {// Object > String// Object > Person > Student// Object > Person > TeacherObject object = new Student();System.out.println(object instanceof Student);			// trueSystem.out.println(object instanceof Person);			// trueSystem.out.println(object instanceof Object);			// trueSystem.out.println(object instanceof Teacher);			// falseSystem.out.println(object instanceof String);			// falsePerson person = new Student();System.out.println(person instanceof Student);			// trueSystem.out.println(person instanceof Person);			// trueSystem.out.println(person instanceof Object);			// trueSystem.out.println(person instanceof Teacher);			// falseSystem.out.println(person instanceof String);			// 编译报错Student student = new Student();System.out.println(student instanceof Student);			// trueSystem.out.println(student instanceof Person);			// trueSystem.out.println(student instanceof Object);			// trueSystem.out.println(student instanceof Teacher);			// 编译报错System.out.println(student instanceof String);			// 编译报错}
    }
    class Person { }
    class Student extends Person { }
    class Teacher extends Person { }
    
  • 对象的类型转换

    父类和子类的优先级:父类是高优先级,子类是低优先级,子类可以自动向父类转换,而父类转换成子类需要强制类型转换

    Person person = new Student();									// 多态
    Student student = (Student)person;								// 将Person类的引用变量转换成Student类的变量
    

Static 关键字

  • 静态属性

    • 静态变量/类变量:归属于类,在内存中只有一个,被所有实例共享,可以通过 类名.属性名 或者 实例名.属性名 调用,推荐前者
    • 非静态变量/实例变量:归属于实例,不同实例相互独立,只能通过 实例名.属性名 调用
  • 静态方法

    • 静态方法/类方法:静态方法内只能调用静态方法
    • 非静态方法/实例方法:非静态方法内可以调用静态方法和非静态方法
  • 静态代码块

    静态代码块随着类一同加载,最先执行,只执行一次

    public class Block {{System.out.print("匿名代码块 ");				// 匿名代码块第二个执行}static {System.out.print("静态代码块 ");				// 静态代码块第一个执行}public Block() {System.out.print("构造方法 ");				// 构造方法第三个执行}public static void main(String[] args) {Block block1 = new Block();Block block2 = new Block();}
    }
    ===================================================================================
    输出结果:
    静态代码块 匿名代码块 构造方法 匿名代码块 构造方法
    
  • 静态导入包

    import 不加 static 修饰时只能导入类,而加了static 修饰后能导入类中的具体方法

    import static java.lang.Math.random;				// 导入Math类中的random方法
    

抽象类

  • abstract 修饰符修饰的方法称为抽象方法,修饰的类称为抽象类
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
  • 抽象类不能使用 new 关键字来创建对象,它是用来让子类继承的
  • 抽象方法只有方法的声明,没有方法的实现,它是用来让子类实现的
  • 子类继承抽象类,就必须要实现抽象类没有实现的抽象方法,否则该类也要声明为抽象类
public abstract class Action {							// Action为抽象类public abstract void doSomething();					// doSomething为抽象方法
}

接口

  • 普通类 vs 抽象类 vs 接口:普通类只有具体实现,抽象类可以有具体实现和规范,接口只有规范

  • 声明类的关键字是 class,声明接口的关键字是 interface

  • 接口中的所有属性默认都是使用 public static final 修饰的常量,所有方法默认都是使用 public abstract 修饰的

  • 接口内的成员变量必须初始化,方法只有声明,方法具体实现通过 “实现类” 完成,实现类必须重写接口中的所有方法

    public interface UserService {							// 接口void run();											// 方法的声明
    }
    
    public class UserServiceImpl implements UserService{	// 实现类,使用implements关键字指明对应的接口@Overridepublic void run() {									// 重写方法// 具体实现}
    }
    
  • 接口可以实现多继承

    public class UserServiceImpl implements UserService, TimeService{// 具体代码
    }
    

内部类

  • 内部类就是在一个类的内部再定义一个类

  • 例如,A类中定义了B类,那么B类相对于A类来说就称为内部类,而A类相对于B类就称为外部类

  • 内部类的分类:成员内部类、静态内部类、局部内部类、匿名内部类

    1. 成员内部类

      public class Application {public static void main(String[] args) {Outer outer = new Outer();Outer.Inner inner = outer.new Inner();				// 成员内部类的实例化}
      }
      class Outer {private int id;public class Inner {									// 成员内部类public void getID(){System.out.println(id);							// 优势:成员内部类可以获得外部类的私有属性/方法}}
      }
      
    2. 静态内部类

      使用 static 对内部类进行修饰,与成员内部类的区别主要在于静态内部类中只能调用静态属性/方法

    3. 局部内部类

      写在方法内的类称为局部内部类

    4. 匿名内部类

      • 匿名对象

        public class Test {public static void main(String[] args) {new Apple().eat();								// 没有变量名,无需将实例保存到变量中}
        }
        class Apple{public void eat(){}
        }
        
      • 匿名接口实现类

        public class Test {public static void main(String[] args) {new UserService(){								// 同样不给定变量名public void hello(){// 接口中方法的具体实现 }};}
        }
        interface UserService {void hello();
        }
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/867941.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自如电费欺诈,屡教不改 All In One

自如电费欺诈,屡教不改 All In One 自如电费欺诈 常见手段汇总 💩 电表示数,自如抄表时候故意多抄、错抄! 导致使用电量和电费暴增,与国家电网 app 查询的实际使用量完全不一致!不严格按照国家和地方的居民电费分档计费标准的价格收费,随意向上跨档高价收费、多收费! …

插件广场

Obsidian 插件集市 (pkmer.cn)

ZooKeeper集群kafka集群安装

kafka的管理需要借助zookeeper完成,所以要先安装好zookeeper集群。 一、zookeeper集群安装 1.1 集群规划 在主机node1、node2和 node3 三个节点上都部署 Zookeeper。 1.2 解压安装 官网下载地址:https://zookeeper.apache.org/这里我安装的版本为3.5.7。在 node1服务器解压 Z…

Lec 12 进程间通信

Lec 12 进程间通信License 本内容版权归上海交通大学并行与分布式系统研究所所有 使用者可以将全部或部分本内容免费用于非商业用途 使用者在使用全部或部分本内容时请注明来源 资料来自上海交通大学并行与分布式系统研究所+材料名字 对于不遵守此声明或者其他违法使用本内容者…

老毛子PADAVAN为何不能挂载大容量移动硬盘/U盘?解决办法竟然如此简单

问题: 我用的是极路由B70,刷了PADAVAN,B70自身带有一个USB2.0,一个USB3.0,插入一个2TB的移动硬盘,NTFS格式,可以识别到,但没有挂载成功。 查看日志, 确实提示挂载失败,然后看到挂载的名字带有一些@@@@@。 解决办法: 联想自己移动硬盘的名字是中文。于是拔下移动硬盘,…

转:python的zmq模块

转自:https://www.jianshu.com/p/04660f746a16https://blog.csdn.net/SweetHeartHuaZai/article/details/1269348191、zmq介绍: 创建和销毁套接字:zmq.socket(), zmq.close() 配置和读取套接字:zmq.setsockopt(), zmq.getsockopt() 为套接字建立连接:zmq.bind(), zmq.conn…

深度强化学习实战:训练DQN模型玩超级马里奥兄弟

深度学习作为当前计算机科学领域最具前沿性的研究方向之一,其应用范围涵盖了从计算机视觉到自然语言处理等多个领域。本文将探讨深度学习在游戏领域的一个具体应用:构建一个能够自主学习并完成超级马里奥兄弟的游戏的智能系统。强化学习基础 强化学习是机器学习的一个重要分支…

导出和导入word样式模板

对于自己配置过之后常用的word样式可以导出作为样式模板, 可以重复使用.举例说一下哪些是常用的word样式, 例如: (常见的): 中文的内容的样式, 中英文分别设置不同的样式 (比较高级的)多级标题自动编号, 题注跟随标题的编号word功能 word自带导出导入模板样式的功能. word样式模…

远程连接和FTP传输问题

遇到的远程连接和FTP传输问题,我们进行了详细调查。以下是我们的分析和建议:远程桌面连接问题:端口检查:默认情况下,Windows系统的远程桌面服务使用的是3389端口。请确保该端口未被防火墙或其他安全软件阻塞。可以通过命令行工具netstat -an | findstr 3389来检查端口状态…

宝塔面板无法登录,如何重置密码并恢复正常访问?

当您遇到宝塔面板无法登录的问题时,可能是由于密码遗忘、凭据错误或服务器配置问题引起的。为了帮助您更好地理解和解决这个问题,以下是几个可能的原因及相应的解决方案:检查凭据是否正确首先,请确认您输入的用户名和密码是否正确。宝塔面板默认的用户名是admin,初始密码通…

网站偶尔无法访问或加载不完全

网站偶尔出现无法访问或无法加载所有网页的情况,这可能是由多种因素引起的。为了帮助您更好地排查和解决问题,建议您按照以下步骤进行检查:检查服务器资源使用情况:首先,确认服务器的带宽、CPU、内存等资源是否正常。可以通过服务器监控工具(如阿里云的云监控)查看实时资…