Java 构造方法(与类同名的方法)、类方法、类变量、实例方法、实例变量
目录
- 一、构造方法
- 1、构造方法的特点:
- 2、构造方法分类
- 3、构造方法的重载
- 4、构造方法中的 this
- 二、类方法、类变量、实例方法、实例变量
- 三、类方法(静态方法,用static修饰的方法)
- 四、类方法与实例方法的区别
- 五、继承和多态
一、构造方法
-
跟类名相同的方法名
被称作构造方法
,其作用是用于当一个类被new成对象时,对象需要声明的一些变量的构造声明。
1、构造方法的特点:
(1)构造方法的名字必须与定义他的类名完全相同(甚至连void也没有),且没有返回类型;
(2)构造方法的调用是在创建一个对象时使用new操作进行的。构造方法的作用是初始化对象
。
Person p = new Person(); : person() 调用的就是Person的构造方法。
(3)每个类可以有零个或多个构造方法;
(4)不能被static、final、synchronized、abstract和native修饰。且构造方法不能被子类继承。
(5)构造方法在创建对象时自动执行
,一般不能显式地直接调用。
2、构造方法分类
(1)默认构造方法 ----老马 p59
// 无参构造方法
class Banana{
public Banana() { System.out.println("无参的构造方法被调用,这里是香蕉"); }
}
public class text3 {
public static void main(String[] args) {
Banana s = new Banana();
}
}
从代码和结果可以看出,“new Banana()” 除了实例化对象,还调用了构造方法Banana();
一旦定义了构造方法,Java就不会再自动生成默认构造方法。
如果只定义了第二个构造方法(带参数的),则下面语句:Point p = new Point();
就会报错,因为找不到不带参数的构造方法。
(2)带参数的构造方法
// 有参构造方法
class Apple{
int size;
public Apple(int a) {
System.out.println("有参的构造方法被调用,这里是苹果");
size = a;
}
public void shuchu() { System.out.println("这个苹果有" + size + "这么大"); }
}
public class text3 {
public static void main(String[] args) {
Apple apple = new Apple(18);
apple.shuchu();
}
}
- 从代码和结果可以看到
Apple(int a)
这是一个有参的构造方法,在new Apple(18)
实例化对象的同时,把参数传给a赋值给size并调用了shuchu()这个构造方法。
(3)私有构造方法:修饰符为 private
场景:
1)不能创建类的实例,类只能被静态访问,如Math、Arrays类,它们的构造方法就是私有的。
2)能创建类的实例,但只能被类的静态方法调用。单例场景。
3)只是用来被其他多个构造函数调用,用来减少重复代码。
3、构造方法的重载
/*
* 构造方法的重载
*/
class Food{
String name;
int size;
public Food(String b , int a) { // 构造函数
name = b;
size = a;
}
public Food(String b) {
name = b;
}
public Food(int a) {
size = a;
}
public void shuchu() {
System.out.println("这个" + name +"有" + size + "这么大");
}
}
public class text4 {
public static void main(String[] args) {
Food s = new Food("苹果");
Food x = new Food("草莓",18);
Food z = new Food(20);
s.shuchu();
x.shuchu();
z.shuchu();
}
}
4、构造方法中的 this
this的第1种用法:this 表示当前实例;
this的第2种用法:调用第2个构造方法;
new Point() 的时候:
(1)分配存放实际数据的内存;
(2)给实例变量设置默认值,new Point() 设置的默认值为0;
(3)调用构造方法(构造函数);
public class Point() {
private int x;
private int y;
public void setX(int x) {
this.x = x; // this.x为实例变量x(无static修饰,能够被实例继承), 右侧的x为方法参数中的x
} // this的第一种用法:this表示当前实例
public void setY(int y) {
this.y = y;
}
public Point() {
this(0, 0); //this的第2种用法:调用第2个构造方法,并传递参数 "0,0"
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
----《Java编程的逻辑》马俊昌 p59
二、类方法、类变量、实例方法、实例变量
(1)类方法:static修饰,静态方法,静态方法是没有this的方法。
(2)类变量:static修饰,静态变量。
(3)实例方法
(4)实例变量
与static相对应的是【实例变量】【实例方法】,没有static修饰符。
Arrays类就只有类方法。 ----《Java编程的逻辑》p54
三、类方法(静态方法,用static修饰的方法)
静态方法
是属于整个类的,所以静态方法
的方法体中,不能有 与类的对象有关的内容(实例对象、实例方法
是属于类的对象)。即类方法体有如下限制:
-
静态方法
只能访问静态变量
,不能访问实例变量
,可以调用其他的静态方法
,不能调用实例方法
。
注释:IDEA中调代码时,main方法就是静态方法,也只能访问静态方法、静态变量。
-
实例方法
既能访问实例变量
,也能访问静态变量
,既可以调用实例方法
,也可以调用静态方法
。 ----《Java编程的逻辑》p55
规定:使用类名来调用静态方法,而不要使用实例或表达式来调用。 ----《Java核心技术 卷I》p117、Java语言编程规范
-
静态方法
不能被覆盖(重写)
;静态方法
中不能使用super,this
关键字; -
实例方法
中可以调用静态方法
;实例方法
中可以使用super,this
关键字;
四、类方法与实例方法的区别
-
静态方法
在加载类时就被分配了内存地址,因此加载后即可被任意对象调用,并且可以通过类名直接调用(类名.方法名)。 -
实例方法
需要在创建对象后才会被分配内存地址,所以实例方法不能通过类名调用。
五、继承和多态
(1)每一个类有且只有一个父类
,没有声明父类的,其父类为Object。
(2)子类继承了父类非private
的属性和方法,可以增加自己的属性和方法,以及重写父类的方法实现。
(3)在 new
的过程中,父类先进行初始化。
(4)
public class Base {
public static String s = "static_base";
public String m = "base";
public static String s_static_base = "s_static_base";
public String m_base = "m_base";
public static void staticTest() {
System.out.println("base static.");
}
public void notStaticTest() {
System.out.println("base not static.");
}
public void notStaticTest_base() {
System.out.println("base_not_static_base.");
}
private void privateTest() {
System.out.println("base private.");
}
}
package org.example;
public class Child extends Base{
public static String s = "static_child";
public String m = "child";
public static String s_static_child = "s_static_child";
public String m_child = "m_child";
public static void staticTest() {
System.out.println("child static.");
}
public void notStaticTest() {
System.out.println("child not static.");
}
public void notStaticTest_child() {
System.out.println("base_not_static_child.");
String s = m_base;
}
private void privateTest() {
System.out.println("child private.");
}
}
public class Test {
public static void main(String[] args) {
Child c = new Child();
Base b = c;
// 重名 静态绑定: 实例变量、静态变量、静态方法、private方法。
// 重写:只用作实例方法(没有static修饰的方法, 属于实例对象的方法,实例对象可对其进行重写。)
// "public VS private"
System.out.println(b.s); // static_base
System.out.println(b.m); // base
System.out.println(c.s); // static_child
System.out.println(c.m); // child
// 实例变量、继承:子类中找不到,就调用父类变量、方法
System.out.println(b.m_base); // m_base(静态绑定)
// System.out.println(b.m_child); // error: Base 中找不到 m_child,不会到子类中去查找:显然不会到子类中去查找。
System.out.println(c.m_child); // m_child(静态绑定)
System.out.println(c.m_base); // m_base
// 子类中没有这个 实例变量,就到父类中寻找。
// 静态变量
System.out.println(b.s_static_base); // s_static_base(静态绑定)
// System.out.println(b.s_static_child); // error: Base 中找不到 s_static_child
System.out.println(c.s_static_child); // s_static_child(静态绑定)
System.out.println(c.s_static_base); // s_static_base
// 子类中没有这个 静态变量,就到父类中寻找。
// 静态方法
b.staticTest(); // base static.(静态绑定)
c.staticTest(); // child static.(静态绑定)
// private方法: 只能在类中访问,不能在外部访问
// b.privateTest(); // error
// c.privateTest(); // error
// 实例方法(属于实例对象的方法):被重写(子类重写与父类相同参数签名的方法)
b.notStaticTest(); // child not static.
c.notStaticTest(); // child not static.
// 实例方法:继承
b.notStaticTest_base();
// b.notStaticTest_child(); // error 找不到
c.notStaticTest_child();
c.notStaticTest_base(); // 子类中没有这个 实例方法,就到父类中寻找。
// 子类继承父类非private的属性和方法(实例变量、实例方法、静态变量、静态方法)
// 静态绑定执行后,在子类中找不到的属性、方法,就到父类中找;父类不能反过来。
// 静态变量、静态方法一般通过类名访问、但是也可以通过类的对象访问。
}
}
推荐阅读
-
Java 构造方法(与类同名的方法)、类方法、类变量、实例方法、实例变量
-
一种结构设计模式,允许在对象中动态添加新行为。它通过创建一个封装器来实现这一目的,即把对象放入一个装饰器类中,然后把这个装饰器类放入另一个装饰器类中,以此类推,形成一个封装器链。这样,我们就可以在不改变原始对象的情况下动态添加新行为或修改原始行为。 在 Java 中,实现装饰器设计模式的步骤如下: 定义一个接口或抽象类作为被装饰对象的基类。 公共接口 Component { void operation; } } 在本例中,我们定义了一个名为 Component 的接口,该接口包含一个名为 operation 的抽象方法,该方法定义了被装饰对象的基本行为。 定义一个实现基类方法的具体装饰对象。 公共类 ConcreteComponent 实现 Component { public class ConcreteComponent implements Component { @Override public void operation { System.out.println("ConcreteComponent is doing something...") ; } } 定义一个抽象装饰器类,该类继承于基类,并将装饰对象作为一个属性。 公共抽象类装饰器实现组件 { protected Component 组件 public Decorator(Component component) { this.component = component; } } @Override public void operation { component.operation; } } } 在这个示例中,我们定义了一个名为 Decorator 的抽象类,它继承了 Component 接口,并将被装饰对象作为一个属性。在操作方法中,我们调用了被装饰对象上的同名方法。 定义一个具体的装饰器类,继承自抽象装饰器类并实现增强逻辑。 公共类 ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component 组件) { super(component); } } public void operation { super.operation System.out.println("ConcreteDecoratorA 正在添加新行为......") ; } } 在本例中,我们定义了一个名为 ConcreteDecoratorA 的具体装饰器类,它继承自装饰器抽象类,并实现了操作方法的增强逻辑。在操作方法中,我们首先调用被装饰对象上的同名方法,然后添加新行为。 使用装饰器增强被装饰对象。 公共类 Main { public static void main(String args) { Component 组件 = new ConcreteComponent; component = new ConcreteDecoratorA(component); 组件操作 } } 在这个示例中,我们首先创建了一个被装饰对象 ConcreteComponent,然后通过 ConcreteDecoratorA 类创建了一个装饰器,并将被装饰对象作为参数传递。最后,调用装饰器的操作方法,实现对被装饰对象的增强。 使用场景 在 Java 中,装饰器模式被广泛使用,尤其是在 I/O 中。Java 中的 I/O 库使用装饰器模式实现了不同数据流之间的转换和增强。 让我们打开文件 a.txt,从中读取数据。InputStream 是一个抽象类,FileInputStream 是专门用于读取文件流的子类。BufferedInputStream 是一个支持缓存的数据读取类,可以提高数据读取的效率,具体代码如下: @Test public void testIO throws Exception { InputStream inputStream = new FileInputStream("C:/bbb/a.txt"); // 实现包装 inputStream = new BufferedInputStream(inputStream); byte bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, len)); } } } } 其中 BufferedInputStream 对读取数据进行了增强。 这样看来,装饰器设计模式和代理模式似乎有点相似,接下来让我们讨论一下它们之间的区别。 第三,与代理模式的区别: 代理模式的目的是控制对对象的访问,它在对象外部提供一个代理对象来控制对原对象的访问。代理对象和原始对象通常实现相同的接口或继承相同的类,以确保两者可以相互替换。 装饰器模式的目的是动态增强对象的功能,而这是通过对象内部的包装器来实现的。在装饰器模式中,装饰器类和被装饰对象通常实现相同的接口或继承自相同的类,以确保两者可以相互替代。装饰器模式也被称为封装器模式。 在代理模式中,代理类附加了与原类无关的功能。
-
如何在 Java 地图中转实体类对象 [与工具类相关的方法
-
1.7 Java 面向对象 [类、对象、方法、面向过程与面向对象的区别
-
Java 学习与实践笔记 (41):字符串类的 API 文档和常用方法
-
Java 类加载器的作用 - 简介:类加载器是 Java™ 中一个非常重要的概念。类加载器负责将 Java 类的字节码加载到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念,包括代理模型、加载类的具体过程和线程上下文类加载器等。然后介绍了如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。 类加载器是 Java 语言的一项创新,也是 Java 语言广受欢迎的重要原因之一。它允许将 Java 类动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 开始出现,最初是为了满足 Java Applets 的需求而开发的,Java Applets 需要从远程位置下载 Java 类文件并在浏览器中执行。现在,类加载器已广泛应用于网络容器和 OSGi。一般来说,Java 应用程序的开发人员不需要直接与类加载器交互;Java 虚拟机的默认行为足以应对大多数情况。但是,如果遇到需要与类加载器交互的情况,而您又不太了解类加载器的机制,就很容易花费大量时间调试异常,如 ClassNotFoundException 和 NoClassDefFoundError。本文将详细介绍 Java 的类加载器,帮助读者深入理解 Java 语言中的这一重要概念。下面先介绍一些基本概念。 类加载器的基本概念 顾名思义,类加载器用于将 Java 类加载到 Java 虚拟机中。一般来说,Java 虚拟机以如下方式使用 Java 类:Java 源程序(.java 文件)经 Java 编译器编译后转换为 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码并将其转换为 java.lang 实例。每个实例都用来表示一个 Java 类。通过该实例的 newInstance 方法创建该类的对象。实际情况可能更加复杂,例如,Java 字节代码可能是由工具动态生成或通过网络下载的。 基本上,所有类加载器都是 java.lang.ClassLoader 类的实例。下面将详细介绍这个 Java 类。 java.lang.ClassLoader 类简介 java.lang.ClassLoader 类的基本职责是根据给定类的名称为其查找或生成相应的字节码,然后根据这些字节码定义一个 Java 类,即 java.lang.Class 类的实例。除此之外,ClassLoader 还负责加载 Java 应用程序所需的资源,如图像文件和配置文件。不过,本文只讨论它加载类的功能。为了履行加载类的职责,ClassLoader 提供了许多方法,其中比较重要的方法如表 1 所示。下文将详细介绍这些方法。 表 1.与加载类相关的 ClassLoader 方法
-
jvm 对 java 类加载机制和类加载器(ClassLoader)、方法区结构、堆实例对象结构的详细解释
-
windows下进程间通信的(13种方法)-摘 要 本文讨论了进程间通信与应用程序间通信的含义及相应的实现技术,并对这些技术的原理、特性等进行了深入的分析和比较。 ---- 关键词 信号 管道 消息队列 共享存储段 信号灯 远程过程调用 Socket套接字 MQSeries 1 引言 ---- 进程间通信的主要目的是实现同一计算机系统内部的相互协作的进程之间的数据共享与信息交换,由于这些进程处于同一软件和硬件环境下,利用操作系统提供的的编程接口,用户可以方便地在程序中实现这种通信;应用程序间通信的主要目的是实现不同计算机系统中的相互协作的应用程序之间的数据共享与信息交换,由于应用程序分别运行在不同计算机系统中,它们之间要通过网络之间的协议才能实现数据共享与信息交换。进程间通信和应用程序间通信及相应的实现技术有许多相同之处,也各有自己的特色。即使是同一类型的通信也有多种的实现方法,以适应不同情况的需要。 ---- 为了充分认识和掌握这两种通信及相应的实现技术,本文将就以下几个方面对这两种通信进行深入的讨论:问题的由来、解决问题的策略和方法、每种方法的工作原理和实现、每种实现方法的特点和适用的范围等。 2 进程间的通信及其实现技术 ---- 用户提交给计算机的任务最终都是通过一个个的进程来完成的。在一组并发进程中的任何两个进程之间,如果都不存在公共变量,则称该组进程为不相交的。在不相交的进程组中,每个进程都独立于其它进程,它的运行环境与顺序程序一样,而且它的运行环境也不为别的进程所改变。运行的结果是确定的,不会发生与时间相关的错误。 ---- 但是,在实际中,并发进程的各个进程之间并不是完全互相独立的,它们之间往往存在着相互制约的关系。进程之间的相互制约关系表现为两种方式: ---- (1) 间接相互制约:共享CPU ---- (2) 直接相互制约:竞争和协作 ---- 竞争——进程对共享资源的竞争。为保证进程互斥地访问共享资源,各进程必须互斥地进入各自的临界段。 ---- 协作——进程之间交换数据。为完成一个共同任务而同时运行的一组进程称为同组进程,它们之间必须交换数据,以达到协作完成任务的目的,交换数据可以通知对方可以做某事或者委托对方做某事。 ---- 共享CPU问题由操作系统的进程调度来实现,进程间的竞争和协作由进程间的通信来完成。进程间的通信一般由操作系统提供编程接口,由程序员在程序中实现。UNIX在这个方面可以说最具特色,它提供了一整套进程间的数据共享与信息交换的处理方法——进程通信机制(IPC)。因此,我们就以UNIX为例来分析进程间通信的各种实现技术。 ---- 在UNIX中,文件(File)、信号(Signal)、无名管道(Unnamed Pipes)、有名管道(FIFOs)是传统IPC功能;新的IPC功能包括消息队列(Message queues)、共享存储段(Shared memory segment)和信号灯(Semapores)。 ---- (1) 信号 ---- 信号机制是UNIX为进程中断处理而设置的。它只是一组预定义的值,因此不能用于信息交换,仅用于进程中断控制。例如在发生浮点错、非法内存访问、执行无效指令、某些按键(如ctrl-c、del等)等都会产生一个信号,操作系统就会调用有关的系统调用或用户定义的处理过程来处理。 ---- 信号处理的系统调用是signal,调用形式是: ---- signal(signalno,action) ---- 其中,signalno是规定信号编号的值,action指明当特定的信号发生时所执行的动作。 ---- (2) 无名管道和有名管道 ---- 无名管道实际上是内存中的一个临时存储区,它由系统安全控制,并且独立于创建它的进程的内存区。管道对数据采用先进先出方式管理,并严格按顺序操作,例如不能对管道进行搜索,管道中的信息只能读一次。 ---- 无名管道只能用于两个相互协作的进程之间的通信,并且访问无名管道的进程必须有共同的祖先。 ---- 系统提供了许多标准管道库函数,如: pipe——打开一个可以读写的管道; close——关闭相应的管道; read——从管道中读取字符; write——向管道中写入字符; ---- 有名管道的操作和无名管道类似,不同的地方在于使用有名管道的进程不需要具有共同的祖先,其它进程,只要知道该管道的名字,就可以访问它。管道非常适合进程之间快速交换信息。 ---- (3) 消息队列(MQ) ---- 消息队列是内存中独立于生成它的进程的一段存储区,一旦创建消息队列,任何进程,只要具有正确的的访问权限,都可以访问消息队列,消息队列非常适合于在进程间交换短信息。 ---- 消息队列的每条消息由类型编号来分类,这样接收进程可以选择读取特定的消息类型——这一点与管道不同。消息队列在创建后将一直存在,直到使用msgctl系统调用或iqcrm -q命令删除它为止。 ---- 系统提供了许多有关创建、使用和管理消息队列的系统调用,如: ---- int msgget(key,flag)——创建一个具有flag权限的MQ及其相应的结构,并返回一个唯一的正整数msqid(MQ的标识符); ---- int msgsnd(msqid,msgp,msgsz,msgtyp,flag)——向队列中发送信息; ---- int msgrcv(msqid,cmd,buf)——从队列中接收信息; ---- int msgctl(msqid,cmd,buf)——对MQ的控制操作; ---- (4) 共享存储段(SM) ---- 共享存储段是主存的一部分,它由一个或多个独立的进程共享。各进程的数据段与共享存储段相关联,对每个进程来说,共享存储段有不同的虚拟地址。系统提供的有关SM的系统调用有: ---- int shmget(key,size,flag)——创建大小为size的SM段,其相应的数据结构名为key,并返回共享内存区的标识符shmid; ---- char shmat(shmid,address,flag)——将当前进程数据段的地址赋给shmget所返回的名为shmid的SM段; ---- int shmdr(address)——从进程地址空间删除SM段; ---- int shmctl (shmid,cmd,buf)——对SM的控制操作; ---- SM的大小只受主存限制,SM段的访问及进程间的信息交换可以通过同步读写来完成。同步通常由信号灯来实现。SM非常适合进程之间大量数据的共享。 ---- (5) 信号灯 ---- 在UNIX中,信号灯是一组进程共享的数据结构,当几个进程竞争同一资源时(文件、共享内存或消息队列等),它们的操作便由信号灯来同步,以防止互相干扰。 ---- 信号灯保证了某一时刻只有一个进程访问某一临界资源,所有请求该资源的其它进程都将被挂起,一旦该资源得到释放,系统才允许其它进程访问该资源。信号灯通常配对使用,以便实现资源的加锁和解锁。 ---- 进程间通信的实现技术的特点是:操作系统提供实现机制和编程接口,由用户在程序中实现,保证进程间可以进行快速的信息交换和大量数据的共享。但是,上述方式主要适合在同一台计算机系统内部的进程之间的通信。 3 应用程序间的通信及其实现技术 ---- 同进程之间的相互制约一样,不同的应用程序之间也存在竞争和协作的关系。UNIX操作系统也提供一些可用于应用程序之间实现数据共享与信息交换的编程接口,程序员可以通过自己编程来实现。如远程过程调用和基于TCP/IP协议的套接字(Socket)编程。但是,相对普通程序员来说,它们涉及的技术比较深,编程也比较复杂,实现起来困难较大。 ---- 于是,一种新的技术应运而生——通过将有关通信的细节完全掩盖在某个独立软件内部,即底层的通讯工作和相应的维护管理工作由该软件内部来实现,用户只需要将通信任务提交给该软件去完成,而不必理会它的具体工作过程——这就是所谓的中间件技术。 ---- 我们在这里分别讨论这三种常用的应用程序间通信的实现技术——远程过程调用、会话编程技术和MQSeries消息队列技术。其中远程过程调用和会话编程属于比较低级的方式,程序员参与的程度较深,而MQSeries消息队列则属于比较高级的方式,即中间件方式,程序员参与的程度较浅。 ---- 4.1 远程过程调用(RPC)
-
标题:什么是类与对象?什么是属性与方法?什么是OOP?什么是类?请对比类和对象实例之间的关系。
-
实操示例:在Java中运用Quality类的方法与技巧