这篇文章主要讲解 Java中的
- 变量
- 方法
- 代码块
- 访问修饰限定符
- Java 是值传递,还是引用传递?
- 类和对象的生命周期.
- ....
希望给您带来帮助
目录
可以在static环境中访问非static变量吗? 为什么 ?
一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?
Java在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是什么
父类的静态方法能否被子类重写(能用Java覆盖静态方法吗?如果我在子类中创建相同的方法是编译时错误?)
变量
成员变量与局部变量的区别
- 语法区别
成员变量是属于对象的,定义在类的内部的,而局部变量是定义在方法内部,或者是作为方法的参数.成员变量可以被public,private,protected,static所修饰,而局部变量不可以.但是成员变量和局部变量都是可以被final所修饰的.
- 存储方式区别
成员变量如果是被static修饰,那么该成员变量属于类 .如果没有被static修饰,那么该成员变量属于对象. 都是存放在堆内存中的,局部变量如果类型是基本数据类型,那么存储在栈内存中,如果是引用数据类型,存放在栈内存的是指向对象的引用地址/指向常量池对象的地址.
- 生命周期区别
对于成员变量,随着对象的创建而创建,销毁而销毁.局部变量随着方法的调用而结束
- 初始值
成员变量会有初始值,而局部变量没有初始值.
静态变量和实例变量的区别?静态方法、实例方法呢?
静态变量与实例变量
- 实例变量/成员变量属于对象,必须创建对象才能调用实例变量(对象.实例变量), 而静态变量被static修饰属于类,调用静态变量使用类.静态变量
- 实例变量/成员变量存放在堆内存中,静态变量存放在方法区中
- 静态变量在类加载时就会被分配存储空间,而实例变量是在创建时才被分配存储空间
静态方法与实例方法
- 静态方法属于类,实例方法属于对象
- 静态方法类加载的时候初始化,实例方法在创建对象的时候初始化
- 实例方法需要通过对象.实例方法来调用, 静态方法既可以使用对象.静态方法(),也可以使用类.静态方法.
- 实例方法既可以调用静态成员,也可以调用实例成员,而静态方法只可以调用静态成员
- 实例方法可以被重写,静态方法不可以被重写.
可以在static环境中访问非static变量吗? 为什么 ?
静态方法中只能调用静态成员,不能调用实例成员,因为被static修饰的是在类加载的时候就初始化了,但是实例成员必须在创建对象的时候才会被初始化,实例成员要比静态成员出现的时机更晚一些.
- 静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
- 在类的非静态成员不存在的时候静态方法就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
字符型常量和字符串常量的区别?
- 形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符。
- 含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。
- 占内存大小:字符常量只占 2 个字节; 字符串常量占若干个字节。
char
在 Java 中占两个字节。
方法
构造方法
一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?
构造方法主要是为对象进行初始化的(为对象的属性赋值);
另外创建对象的时候包含3步
- 为对象分配内存空间
- 调用对象构造方法为对象初始化
- 给对象的属性(实例变量)赋值
所以构造方法的调用是创建对象的一部分,在Java中初始化和创建两者不能分离.创建对象的时候就会自动调用构造方法(由编译器自动调用).
如果一个类没有声明构造方法,编译器会自动为该类生成一个无参的构造方法,确保每一个对象进行初始化. 当然如果一个类本身就有构造方法,那么编译器就不会为其自动生成了.
构造方法有哪些特点?是否可被 override?
- 构造方法的名字必须与类名相同
因为要让编译器找到这个构造方法,并且还不能与其他成员命名冲突,所以与类名相同
- 构造方法没有返回值
如果具有返回值,那就得让编译器知道如何处理这个返回值
- 构造方法是在创建对象的时候由编译器执行,无需/不能手动调用
- 构造方法不可以被重写,但是可以被重载.
为什么 构造方法不可以被重写,但是可以被重载 ?
首先方法重写是针对子类重写父类的方法. 但是构造方法的名称必须与类名相同,如果允许子类重写父类的构造方法,那么子类的类名必须与父类的类名是一致的, 矛盾,不成立.
而对于方法重载是针对同一个方法名的,我们已经成看到一个类中有多个构造方法(不同参数的);
讲一讲私有的构造方法
Java在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是什么
因为子类也继承了父类的成员,所以是帮助子类进行初始化
父类的静态方法能否被子类重写(能用Java覆盖静态方法吗?如果我在子类中创建相同的方法是编译时错误?)
首先说一下结论,子类不能重写父类的静态方法(不能重写静态方法),因为静态方法是属于类的,无论在父类还是在子类,静态方法的行为是一致的,都是属于这个类本身的,如果子类定义了与父类相同名字,返回值,参数列表的静态方法,这并不是重写,而是在子类新定义了一个静态方法.
如果子类创建了相同的实例方法 : -->代表是重写
如果子类创建了相同的静态方法 :只是新定义了一个静态方法,不会报错, 因为静态方法属于类本身的.不会发生编译时错误.
重写和重载的区别
-
重载就是同样的一个方法根据输入数据的不同,做出不同的结果
-
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法
重载 :
在同一个类中,多个方法具有相同的名称,但是参数列表不同,这样的不同参数的方法,互相称之为重载方法
重载条件 :
- 相同的方法名称
- 不同的参数列表
- 被重载的方法可以改变返回类型
- 被重载的方法可以改变访问修饰符
- 被重载的方法可以声明新的或者更广的异常
- 方法能够在同一个类或者一个子类中被重载
- 发生在编译器
怎么实现方法重载的 ?(根据什么来区分不同的方法的?)
编译器必须挑选出具体执行哪个方法,它通过用各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出相应的方法。 如果编译器找不到匹配的参数, 就会产生编译时错误, 因为根本不存在匹配, 或者没有一个比其他的更好(这个过程被称为重载解析。
Java 允许重载任何方法, 而不只是构造器方法。
编译器是根据方法签名(根据方法名称,参数顺序,参数类型来确定)来确定具体调用哪个方法.(区分方法)
重写:
重写是指在Java的子类与父类中,有两个名称相同并且参数列表相同的方法,由于他们具有相同的方法签名,所以子类的新方法将会覆盖父类中原有的方法
-
方法名,参数列表必须相同. 子类方法返回值类型应该比父类方法返回值类型更小或者相等. 抛出的异常范围小于父类. 访问修饰符范围大于等于父类. (方法的返回类型是void和基本数据类型,返回值重写时不可以修改,如果方法是引用类型,重写时是可以返回该引用的子类或者与父类返回值相同)
-
如果父类方法访问修饰符为 private/final/static, 则子类就不能重写该方法,但是被static修饰的方法能够被再次声明.
-
构造方法无法被重写
-
如果不能继承一个方法,就不能重写这个方法
-
发生在运行期
重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变.
什么是方法的返回值?返回值在类的方法里的作用是什么?
方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作!
代码块
实例代码块
- 实例代码块优先于构造方法先执行。 从字节码的角度看,编译器是把实例代码块的代码拷贝到构造方法之前编译。
- 当没有创建对象的时候,实例代码块和构造方法不会被执行。(实例代码块只有在创建对象时才会执行)
静态代码块
- 代码块执行顺序是 静态代码块优先于实例代码块优先于构造方法执行。
- 静态代码块只保留一份。这证明当有多个static代码块时会根据优先顺序执行,初始化结果会发生覆盖,后面的覆盖前面的。
- 静态代码块不管生成多少个对象,其只会执行一次
代码块和构造方法的(执行/初始化)顺序
初始化顺序:父类静态代码块>子类静态代码块>父类实例代码块>父类构造方法>子类实例代码块>子类构造方法。如果是第二次实例化对象,那就没有静态代码块。
访问修饰限定符
Java 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。可以修饰在类、接口、变量、方法。
- private : 在同一类内可见。可以修饰变量、方法。注意:不能修饰类(外部类)
- public : 对所有类可见。可以修饰类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。可以修饰变量、方法。注意:不能修饰类(外部类)。
Java 是值传递,还是引用传递?
无论是值传递还是引用传递都是求值策略(定义以何时,何种顺序传值给函数的实际参数,以及什么时候将他们带入到函数,代还以何种形式发生)的一种
除了引用传递,值传递,还有共享对象传递
值传递是指在调用函数的时候把实际参数复制一份传到这个调用的函数中,如果这个函数对参数进行修改,将不会影响到实际参数.(形参是实参的一份临时拷贝)(先通过求值,,再将值赋值,传递给被调函数的形式参数)
引用传递是指调用函数的时候把实际参数的地址传递到这个调用的函数中,如果这个函数对参数进行修改,因为实际参数引用与副本引用指向的是同一个对象,所以会影响到实际参数.
共享对象传递 : 先获取实际参数的地址,然后将其复制,并把地址的副本传递给被调函数的形式参数.也是值传递的一种特例.
区分值传递还是引用传递主要是看传递给方法的是实际参数的副本还是实际参数的地址(传递的是副本还是直接传递).如果传递的是副本就是值传递,否则就是引用传递.
Java中求求值策略是共享对象传递(值传递).(实参和形参指的是同一个共享对象)
对于Java只是把对象的引用当做值 传递给方法, 也可以理解为是一种共享对象传递(是值传递的一种特例.) Java会将对象的地址的副本传递给方法
所以, Java中只有值传递,只不过传递的内容是对象的引用.
Java 值传递详解 | JavaGuide(Java面试 + 学习指南)