类、对象和引用的关系

类和对象的关系

  • 类是对象的模版,对象是类的一个实例,一个类可以有很多对象
  • 一个Java程序中类名相同的类只能有一个,也就是类型不会重名
  • 一个对象只能根据一个类来创建

引用和类以及对象的关系

  • 引用只能指向其所属的类型的类的对象
  • 相同类型的引用之间可以赋值
  • 只能通过指向一个对象的引用,来操作一个对象,比如访问某个成员变量

方法

参数传递方式

Java 总是采用按值调用

基本类型的值传递

public class PrimitiveTransferTest { public static void swap(int a, int b) { int tmp = a; a = b; b = tmp; System.out.println("swap 方法里 a 的值为: " + a + " b的值为: " + b); } public static void main(String[] args) { int a = 6; int b = 9; swap(a, b); System.out.println("交换结束后 a 的值为 " + a + " b的值为 " + b); }}/**运行结果:swap 方法里 a 的值为: 9 b的值为: 6交换结束后 a 的值为 6 b的值为 9*/

分析图:

java 程序总是从 main() 方法开始执行,main() 方法定义了 a、b 两个局部变量,两个变量在 main 栈区中。在 main() 方法中调用 swap() 方法时,main() 方法此时还未结束,因此系统为 main 方法和 swap 方法分配了两块栈区,用于保存 main 方法和 swap 方法的局部变量。main 方法中的 a、b 变量作为参数传入 swap 方法,实际上是在 swap 方法栈区中重新产生了两个变量 a、b,并将 main 方法栈区中 a、b 变量的值分别赋给 swap 方法栈区中的 a、b 参数(这就是初始化)。此时系统内存中有两个 a 变量、两个 b 变量,只是存在于不同的方法栈区中而已。

引用类型的参数传递

public class ReferenceTransferTest { public static void swap(DataWrap dw) { int tmp = dw.a; dw.a = dw.b; dw.b = tmp; System.out.println("swap 方法里, a 成员变量的的值为: " + dw.a + " b 成员变量的值为: " + dw.b); } public static void main(String[] args) { DataWrap dw = new DataWrap(); dw.a = 6; dw.b = 9; swap(dw); System.out.println("交换结束后, a 成员变量的的值为: " + dw.a + " b 成员变量的值为: " + dw.b); }}/**swap 方法里, a 成员变量的的值为: 9 b 成员变量的值为: 6交换结束后, a 成员变量的的值为: 9 b 成员变量的值为: 6*/

你可能会疑问,dw 对象的成员变量 a、b的值也被替换了,这跟前面基本类型的传递完全不一样。这非常容易让人觉得,调用传入 swap 方法的就是 dw 对象本身,而不是它的复制品。其实传递的依然是 dw 的值。

分析图:

系统一样赋值了 dw 的副本,只是关键在于 dw 只是一个引用变量,它存储的值只是一段内存地址,将该内存地址传递给 swap 栈区,此时 swap 栈区的 dw 和 main 栈区的 dw 的值也就是内存地址相同,该段内存地址指向堆内存中的 DataWrap 对象。对 swap 栈区的 dw 操作,也就是对 DataWrap 对象操作。

重载

重载:同一个类中,方法名相同,参数列表不同。

当调用被重载的方法时,根据参数的个数和类型判断应该调用哪个重载方法,参数完全匹配的方法将被执行。

构造器

默认无参构造器

仅当类没有定义任何构造器的时候,系统才会提供一个默认的构造器。这个构造器将所有的实例域设置为默认值。

自定义构造器

当类中有自定义构造器时,系统不会再提供默认的构造器

静态常量

public static final double PI = 3.1415926

静态方法

在类加载的时候就存在了,不依赖于任何类的任何实例。

建议通过类名调用,而不是通过实例对象调用,否则很容易混淆概念。

继承

java 使用 extends 作为继承的关键字,有趣的是 extends 是扩展的意思,并不是继承。但是 extends 很好体现了子类和父类的关系,子类是对父类的扩展,子类是一种特殊的父类。扩展更加准确。ps:这个理解真的是流弊啊。

子类重写父类方法(覆盖)

方法的重写遵循 “两同两小一大”规则:

  • 方法名相同、形参列表相同
  • 子类方法返回的值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应该比父类方法声明抛出的异常类更小或相等
  • 子类方法访问权限应该比父类方法的访问权限更大或相等

子类中调用父类被覆盖的方法

  • 如果被覆盖的方法是实例方法,使用 super 关键字
  • 如果被覆盖的方法是类方法,使用父类类名
  • 子类不能调用父类中被 private 修饰的方法和属性

子类调用父类构造器

  • 子类不能继承父类的构造器。在子类的构造器中,如果没有显式使用 super 调用父类的构造函数,那么系统一定会在子类构造器执行之前,隐式的调用父类的无参构造器
  • 在子类构造器中,可以使用 super 显式调用父类构造器,但 super 语句必须在第一行

多态

向上类型转换

Java 引用变量有两个类型。如果编译时类型和运行时类型不一致,就可能出现多态。

  • 编译时类型:由声明该变量时使用的类型决定
  • 运行时类型:由实际赋给该变量的对象决定

示例代码:

public class BaseClass { public int book = 6; public void base() { System.out.println("父类的普通方法"); } public void test() { System.out.println("父类的test方法"); }}public class SubClass extends BaseClass { public String book = "轻量级 Java EE"; public void test() { System.out.println("子类的test方法"); } public void sub() { System.out.println("子类的sub方法"); } public static void main(String[] args) { BaseClass ploymophicBc = new SubClass(); System.out.println(ploymophicBc.book); ploymophicBc.base(); ploymophicBc.test(); // 因为 ploymophicBc 的编译时类型是 BaseClass // BaseClass 类没有提供 sub 方法,所以下面代码编译时会出错 // ploymophicBc.sub(); }}

上面的例子中,引用变量 ploymophicBc 比较特殊,它的编译时类型是 BaseClass,而运行时类型是 SubClass。

ploymophicBc.sub() 这行代码会在编译时报错,因为 ploymophicBc 编译时类型为 BaseClass,而 BaseClass 中没有定义 sub 方法,因此编译时无法通过。

但是注意,ploymophicBc.book 的值为 6, 而不是 ”轻量级 Java EE“。因为对象的实例变量不具备多态性,系统总是试图访问它编译时类型所定义的成员变量,而非运行时。

子类其实是一种特殊的父类,因此 java 允许把父类的引用指向子类对象,这被称为向上转型(upcasting),向上转型由系统自动完成。

可以调用哪些方法,取决于引用类型(编译时)。

具体调用哪个方法,取决于引用指向的实例对象(运行时)。

向下类型转换

问题:引用变量在代码编译过程中,只能调用它编译时类型具备的方法,而不能调用它运行时类型具备的方法

解决:强制转换成运行时类型

方法:引用类型之间的转换只能在有继承关系的两个类型之间进行,否则编译出错。如果想把一个父类引用变量的编译时类型转换成子类类型,则这个引用变量的运行时类型得是子类类型,否则引发 ClassCastException

示例代码:

//创建子类对象 Dog dog = new Dog(); // 向上类型转换(类型自动提升),不存在风险 Animal animal = dog; // 风险演示 animal 指向 Dog 类型对象,没有办法转化成 Cat 对象,编译阶段不会报错,但是运行会报错Cat cat = (Cat)animal; // 1.编译时按 Cat 类型 2. 运行时 Dog 类型,类型不匹配,直接报错 

instanceof

为了解决强制类型转换,可能引发的 ClassCastException 异常,引入 instanceof 运算符。

instanceof 运算符的含义:用于判断左边的对象(运行时类型或者叫实际类型)是否是右边的类或者其子类、实现类的实例。如果是返回 true,否则返回 false。

在之前的代码中,强制类型转换前使用 instanceof 判断:

if (anmial instanceof Cat) { Cat cat = (Cat)animal;}

final 修饰符

final 修饰类

不能被继承

final 修饰方法

不可被子类覆盖

final 修饰变量

特征:变量一旦被初始化,便不可改变

初始化:定义时直接赋值、借助构造函数

对于基本类型域而言,其值是不可变的。

对于引用类型变量而言,它保存的仅仅只是个引用。final 只保证这个变量所引用的地址不会改变,即一直引用同一个对象。但这个对象自身内容完全可以发生改变。

Object 类

toString

toString 用于输出对象的自我描述信息。

Object 类提供的 toString 返回该对象实现类的 "类名 + @ + hashCode"。通常需要重写该方法。

==

对于数值类型的基本变量,只要两个变量的值相等(不需要数据类型完全相同),就返回 true。

对于两个引用类型的变量,只有它们指向同一个对象时,== 判断才会返回 true。

equals

equals 方法是 Object 类提供的一个实例方法。对于引用变量,只有指向同一个对象时才返回 true。一般需要重写 equals 方法。

重写 equals 方法的示例:

 public boolean equals(Object obj) { if (this == obj) { return true; } if (obj !=null && obj.getClass() == Person.class) { Person personObj = (Person)obj; if (this.getIdStr().equals(personObj.getIdStr())) { return true; } } return false; }

equals 为 true,hashCode 就应该相等,这是一种约定俗称的规范。即 equals 为 true 是 hashCode 相等的充分非必要条件。

接口

设计思想

  • 接口体现的是规范和实现分离的设计哲学,让软件系统的各组件之间面向接口耦合,是一种松耦合的设计
  • 接口定义的是多个类共同的公共行为规范,这些行为是与外部交流的通道,意味着接口通常是定义一组公共方法

定义

  • 接口的修饰符,只能是 public 或者 default
  • 由于接口定义的是一种规范,所以接口里不能包含构造器和初始化块定义,只能包含静态常量、方法(只能是抽象方法,类方法和默认方法)以及内部类、内部接口、内部枚举
  • 接口里的常量只能是静态常量,默认使用 public static final 修饰
  • 接口里的内部类、内部接口、内部枚举,默认使用 public static 修饰
  • 接口里的抽象方法不能有方法体,但类方法和默认方法必须有方法体。

方法说明

接口中定义抽象方法可以省略 abstract 关键字和修饰符,默认修饰符为 public。

Java 8 新增允许在接口中定义默认方法,使用 default 修饰。默认情况下,系统使用 public 修饰默认方法。

Java 8 新增允许在接口中定义私有方法。

Java 8 新增允许在接口中定义静态方法。静态方法可以被实现的接口的类继承。

使用

一个类可以实现一个或多个接口。

一个类实现一个或多个接口,这个类必须重写所实现的接口中的所有抽象方法。否则,该类必须被定义成抽象类,保留从父接口继承到的抽象方法。

接口不能用来创建实例,但是可以用于声明引用类型的变量,该变量必须指向实现该接口的类的实例对象。

抽象类

抽象类与普通类的区别,可以概括为 “有得有失”。

得,是指抽象类多了一个能力,抽象类可以包含抽象方法

失,是指抽象类失去了一个能力,抽象类不能用于创建实例

抽象类和普通类的区别:

  • 抽象类使用 abstract 修饰
  • 抽象类可以和普通类一样可以包含成员变量、方法、构造器、初始化块、内部类。但抽象类不能被实例化,抽象类的构造器主要用来被子类调用
  • 抽象类可以不包含抽象方法,但是含有抽象方法的类必须被定义为抽象类

抽象类的设计思想:抽象类是模板模式的设计模式体现。抽象类是从多个具体类中抽象出来的父类,具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类为其子类的模板,避免子类设计的随意性

内部类

成员内部类

非静态内部类

public class Cow { private double weight; public Cow() { } public Cow(double weight) { this.weight = weight; } // 定义一个非静态内部类 private class CowLeg { private double length; private String color; public CowLeg() {} public CowLeg(double length, String color) { this.length = length; this.color = color; } public double getLength() { return this.length; } public void setLength(double length) { this.length = length; } public String getColor() { return this.color; } public void setColor(String color) { this.color = color; } public void info() { System.out.println("当前牛腿的颜色是 " + this.color + 

不能将brassplus类型的值分配到brass类的实体_Java 基础 - 类与对象相关推荐

  1. 不能将brassplus类型的值分配到brass类的实体_GO的类型系统和类型的方法

    GO的类型系统和类型的方法 [TOC] 1. 类型及其作用 2. 用户自定类型(两种实现) 3. 类型的方法 4. 类型的本质 5. 嵌入类型 0 前言 如果说goroutine和channel是撑起 ...

  2. 不能将X*类型的值分配到X*类型的实体问题的解决方法

    不能将X类型的值分配到X类型的实体问题的解决方法 今天在学习链表的过程中,遇到了这样一个问题 1.代码如下: typedef struct {ElemType data;struct LNode *n ...

  3. getch()与_getch()、不能将const char*类型的值分配到const* 类型的实体

    参考1:getch()与_getch() 添加预处理 项目 -> 属性 -> 配置属性 -> C/C++ -> 预处理器 -> 预处理器定义 -> 编辑中添加:_C ...

  4. Vs调试报错:不能将 “const char *“ 类型的值分配到 “char *“ 类型的实体

    设置为否 即可成功编译 参考博文 CSDN博主「骑码学GIS」的原创文章

  5. 布尔类型的值包括( )和( )_布尔类型

    2.4.3布尔类型 布尔类型主要用来表示真值或假值.在Python中,标识符True和False被解释为布尔值.另外,Python中的布尔值可以转化为数值,True 表示1, False 表示0. 说 ...

  6. 关于C#值类型,引用类型,值传递,引用传递

    说到参数传递,必须得弄清值类型和引用类型: (为了容易表达,我暂且命名存放在堆中的内容为堆中对象,存放在栈上的内容为栈中对象.) 值类型存放在栈中,直接访问.如果有:int a=0;int b=a;就 ...

  7. ext如何将值存入变量_变量类型之值类型与引用类型

    前言 变量类型在我们日常开发中经常接触到,但是js中的变量类型与其他强类型语言不同,由于js是弱类型语言,因此他的变量拷贝在我们实际的日常开发中有很多需要注意的项.而半斤在最近的开发中遇到了很多匪夷所 ...

  8. C#中的变量类型(值类型、引用类型)

    C#中的变量类型: 值类型:值类型直接存储的是变量的值,变量空间在栈上分配,分配速度比较快.给变量赋值时需注意变量类型的取值范围,给变量赋不合理的值会导致编译器报错.布尔类型的变量只有两种可选择的值t ...

  9. lua学习之类型与值篇

    类型与值 lua 是动态类型的语言 在语言中没有类型定义的语法 每个值都携带有它的类型信息 8种基础类型 用 type 可以返回这个值的类型的名称 将一个变量用于不同类型,通常会导致混乱的代码 但合理 ...

最新文章

  1. Django之初步实现登录功能,APP及ORM
  2. 《一个程序员的奋斗史》正式上架~
  3. php显示前60个字,DEDECMS中怎么让文章标题栏突破60个字符
  4. mysql批量写入100万数据_Mysql数据库实践操作之————批量插入数据(100万级别的数据)-阿里云开发者社区...
  5. 以企业面试讲解sql语句
  6. Python脚本实现启停app获取资源占比信息
  7. Editplus中添加System.out.println()快捷键
  8. mfc110.dll丢失,解决方法
  9. java udp server_实现java UDP Server --2008农历新年第一贴(原创)
  10. 不能创建对象qmdispatch_运行时错误 429,ACTIVEX部件不能创建对象的解决方法小结...
  11. express+socket.io 共享session
  12. 海康摄像头实时显示与字符叠加详解
  13. PHP新闻内容分页类
  14. java时间戳与LocalDateTime常用转换方式
  15. 有些人光是活着就已经是拼尽全力了
  16. 80页PPT | 智能制造工厂三年规划(附下载)
  17. 【Linux系统管理】05 常用命令 06 vim编辑器
  18. 【MySQL体系结构】MySQL8.0物理文件结构
  19. SetWindowPos 函数的含义及用法
  20. 扩展金山提示框,使之带颜色(二)

热门文章

  1. POJ 1002 487-3279
  2. [再寄小读者之数学篇](2014-07-27 $H^{-1}$ 中的有界集与弱收敛极限)
  3. 【思维智慧】007.利用贪婪的人身上的破绽
  4. 常数中有换行符的错误
  5. Git如何处理代码冲突
  6. 容器编排技术 -- Kubernetes kubectl 命令表
  7. RHEL/CentOS 7中安装并配置 PowerDNS 和 PowerAdmin
  8. Hibernate Validator JSR303示例教程
  9. php获取apk中文应用名,php提取apk包信息 - 搜知道网 - 搜知道社区,C, iOS,Android,golang 等的知识....
  10. 熊猫站群1.0 开发完结