Java 是面向对象的程序设计语言,类是面向对象的重要内容,可以把了当成一种自定义类型。可以使用类来定义变量,这种类型的变量统称为引用变量。
static 是一个特殊的关键字,它可用于修饰方法,成员变量等成员。static 修饰的成员表明他属于这个类本省,而不属于该类的单个实例,因为通常把 static 修饰的成员变量和 方法 也成为类变量,类方法。不使用 static 修饰的普通方法,成员变量则属于该类的单个实例,而不属于该类。因为通常把不使用 static修饰的成员变量和方法也成为实例变量,实例方法。
对象的this引用是什么?
Java 提供了一个this 关键字,this关键字总是指向调用该方法的对象,更具 this 出现位置的不同,this作为对象的默认引用有两种情形。
- 构造器中引用该构造器正在初始化的对象
- 在方法中引用调用该方法的对象。
this关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或实例变量。
this可以代表任何对象,当this出现在某个方法体重是,它所代表的对象是不确定的,但它的类型是确定的,他所代表的对象 只能是当前类;只有当这个方法被调用时,它所代表的对象才被确定下来,谁在调用这个方法,this就代表谁。
大部分时候,一个方法访问该类中定义的其他方法,成员变量时加不加this前缀的效果是完全一样的。但是对于static 修饰的方法而言,则可以使用类来直接调用该方法,如果在 static 修饰的方法中使用 this关键字,则这个关键字就无法指向合适的对象。所以,satatic 修饰的方法不能使用 this引用,所以static 修饰的方法不能访问不使用 static 修饰的普通成员,因此 Java 语法规定: 静态成员不能直接访问非静态成员。
也可以将 this 作为返回值,如果某个方法把 this 作为返回值,则可以多次连续调用同一个方法,从而使得代码更加简洁。但是,这种把 this作为返回值的方法可能造成实际意义上的模糊。
public class MyClass { private static int age; public static void main(String[] args) { new MyClass().vo().vo().vo(); } private MyClass vo() { ++age; System.out.println(age); return this; } }
为什么static成员不能直接访问非静态成员?
static 是一个特殊的关键字,它可用于修饰方法,成员变量等成员。static 修饰的成员表明他属于这个类本身,而不属于该类的单个实例。而我们非static 修饰的变量它属于的是实例的变量,所以stati成员不能直接
访问静态成员
为什么同一类里,静态和非静态方法可以相互调用?
因为Java里的方法不能独立存在,他必须属于一个类或一个对象,因此方法不能像函数那样被独立执行,执行方法时必须使用类或对象来作为调用者,同一个类的一个方法调用另外一个方法时,如果被调方法时普通方法,则使用默认使用 this 作为调用者;如果被调方法是静态方法,则默认使用类作为调用者。也就是说,表面上看起来某些方法可以被独立执行,但实际上环视使用this或者 类 作为调用者。
Java的参数传递中可以引用传递吗?
不可以,Java的参数传递方式只有一种,值传递。所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到影响。
我们有时候见到 使用 参数传递 某些对象。看起来好像是引用传递,但其实不是,这里传递的也只是一个对象在内存中的的地址而已,并不是真正的把 对象引用传递过去。
形参个数可变的参数是什么?
Jdk1.5 之后,Java允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参。如果在定义方法时,在最后一个形参的类型后增加三点 (…),则表明该形参可以接受多个参数值,多个参数值被当成数组传入。
public class MyClass { private static int age; public static void main(String[] args) { Demo(2,3,4); Demo(new int[]{12,2}); } static void Demo(int... a2) { for (int i : a2) { System.out.println(i); } } }
但需要注意的是,长度可变的形参只能处于形参列表的最后。一个方法最多只能包含一个长度可变的形参。长度可变的形参本质就是一个数组类型的形参,因此调用包含一个长度可变形参的方法时,这个长度可变的形参即可以传入多个参数,也可以传入一个数组。
为什么方法的返回值类型不能用于区重载的方法?
对于 int f()和 void f() 两个方法,如果 int a=f(),系统可以识别是调用返回值类型为 int 的方法;但Java 调用方法时 可以忽略 方法的返回值,如果直接调用 f(),那么谁有知道到底是调用了那个方法呢?
为什么需要添加set get方法?
Java类里实例变量的 set 和get方法有着非常重要意义,例如,某个类里包含了一个名为 abc 的实例变量,则其对应的 set和get 方法名应为setAbc() 和 getAbc().
如果一个类 Java 类的每个实例 变量都被使用 private 修饰,并为每个实例变量都提供了 public 修饰的 set 和 get方法,那么这个类就是一个 符合 JavaBean 规范的类,因此,JavaBean 总是一个封装良好的类。
一个类常常就是一个小的模块,应该只让这个模块公开必须让外界知道的内容,而隐藏其他的一切内容。进行程序设计时,应尽量避免一个模块直接操作和访问另一个模块的数据,模块设计追求高内聚(尽可能把模块之间的内部数据,功能实现细节隐藏在模块内部独立完成,不允许外部直接干预),低耦合(仅暴露少量的方法给外部使用)。
构造器创建Java对象的途径,是不是说构造器完全负责 Java对象?
不是,构造器是创建 Java 对象的重要途径,通过 new 关键字调用构造器时,构造器也确实返回了 该类的对象,但这个对象并不是完全由构造器负责创建的。实际上,当程序员调用构造器时,系统会先为该对象分配内存空间,并为这个对象执行默认初始化,这个对象已经产生了——这些操作系统在构造器的执行前就都已经完成了。也就是说,当系统开始执行构造器的执行体之前,系统已经创建了一个对象,只是这个对象还不能被外部程序访问,只能在该构造器中通过this 来引用。当构造器的执行体结束后,这个对象作为构造器的返回值而被返回,通常还会赋给另一个引用类型的变量,从而让外部程序可以访问该对象。
super限定的用处?
如果需要在子类方法中调用 父类被覆盖的实例方法。则可使用 super 限定来调用父类被覆盖的实例方法。
package com.example.javatest; public class Demo extends A{ public static void main(String[] args) { new Demo().test(); } public void test(){ super.test(); System.out.println("Demo"); } } class A{ public void test(){ System.out.println("A"); } }
什么是多态?
Java 引用变量有两个类型,一个是编译型类型,一个是运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给变量的对象决定。如果编译时类型和运行时类型不一样。就可能出现所谓的多态。
当把一个子了i对象那个直接赋给父类引用变量时,运行时调用该引用变量的方法是,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征。
instanceof 运算符是干什么的?
判断是否是可以成功转换
instanceof 运算符的前一个操作数通常是一个 引用类型变量,后一个操组数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类),它用于判断前面的对象是否是后面的类,或者其子类,实现类的实例。如果是,返回 true,否则 返回false
public class Demo { public static void main(String[] args) { Object a=new String("123"); if (a instanceof Integer) { System.out.println("123"); } } }
谈谈你对继承的理解?
继承最大的好处就是类的复用性,子类可以直接调用父类的所有成员变量和方法。但是继承带来高度复合的同事,也带来了一个严重的问题:继承严重破坏了父类的封装性。Java 里对封装的定义是:每个类都应该封装它内存信息和实现细节,而只暴露必要的方法给其他类使用。但在继承关系中,子类可以直接访问父类的成员变量(内部信息)和方法,从而造成子类和父类的严重耦合。
所以我们在使用继承的时候。首先得明白:子类是一种能特殊的父类。
对于具备以下条件之一才使用继承,否则使用 组合 也能实现类的复用。
- 子类需要额外增加属性,而不仅仅是属性值的改变。
- 子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)
谈谈你对组合的理解?
把一个类当做一个类的组合成分,从而允许新类直接复用该类的 public 方法,这种就是组合。
一般用到组合的地方,用继承也可以实现,简单来说,继承是对已有类的一番改造,以此获得一个特殊的类。简而言之,就是将一个较为抽象的类改造成能适用于某些特定需求的类,比如在原来基础上增加别的成员变量或者方法等。反之,如果两个类之间有明确的整体,部分的关系,此时就应该采用组合关系来实现复用。
总之,继承要表达的是 (is-a)的关系,而组合表达的是 有 (has-a)的关系。(is-a代表的是继承关系,has-a代表的是对象和它成员的从属关系)
什么是自动装箱?
自动装箱,就是可以把一个基本类型变量直接赋给对应包装类变量,或者赋给Object变量,(Object是所有类的父类,自诶对象可以直接符给父类变量),自动拆箱则则与之相反,允许直接·把包装类对象直接赋给一个对应的基本类型变量。
简单讲一下==与 equals 方法有什么不同?
Java程序测试两个变量是否相等有两种方式,一种是利用== 运算符,另一种就是利用 equals方法,当时用 判断两个变量是否相等时,如果两个变量时基本类型变量,且都是数据类型,则只要两个变量的值相等,就将返回 true。但对于引用类型变量,只要他们指向同一个对象, 判断才会返回true,== 不可用与比较类型上没有父子·关系的两个对象。euqals 判断的是引用对象里包含的字符序列是否相同,相同就返回true,
简单讲一下 final 修饰符
final修饰符可用于修饰类,变量和方法。final 修饰的变量度不可被改变,一旦获得了初始值,该 final 变量的值就不能被重新赋值。final修饰的成员变量必须由程序员显示的指定初始值,因为系统不会为 final 修饰的变量隐式初始化。
final修饰基本引用类型和运用类型变量有什么区别?
当时用final 修饰基本类型数据时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final 只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。
为什么被final修饰的变量 被称为 执行宏替换 的变量?
当定义final 变量时就为该变量指定了初始值,而且该初始值可以在编译期间确定下来,那么这个 final 变量本质上就是一个 宏变量 ,编译器会把程序中所有用到该变量的地方直接替换为该变量的值。
谈谈你对抽象类与抽象方法的理解?
- 抽象类必须是 abstact 修饰符来修饰,抽象方法也必须使用 abstract 修饰符来修饰,抽象方法不能有方法体。
- 抽象类·不能被实例化,无法使用 new 关键字来调用 抽象类的构造器创建抽象类的实例。
- 抽象类可以包含成员变量,方法(普通方法和抽象方法都可以),构造器,初始化块,内部类(接口,枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
- 含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象方法,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。
需要注意的是:
- static 和 abstract 不能同时修饰某个方法。
- static 和 abstract 可以同时修饰内部类
- abstract 关键字修饰的方法必须被其子类重写才有意义,否则这个方法将永远不会有方法体。