java类和对象面经
面向对象和面向过程的区别
面向过程:优点:性能更好,广泛应用于单片机,嵌入式,Linux等需要注重性能的场景。原因是面向对象的语言需要将类实例化,资源消耗比较大,所以在注重性能的场景下一般使用面向过程的语言
面向对象:优点:易复用,易维护,易扩展。因为面向对象又封装,继承,多态等特性,所以可以设计出低耦合度的程序,使得维护和扩展更加方便,同时面向对象更容易复用,编写一个类可以实现多个对象。
当然,java不一定性能就一定比面向过程的语言性能差。但是由于语言特性,java不会直接编译成机器语言,而面向过程的语言会直接编译成机器能识别的语言,所以一般来说面向过程的语言性能会更好一些,当然并不绝对!
构造器是否可以被Override
构造器不可以被Override,但是可以被重载。
对构造器Override也没有意义,因为不会有两个类有同样的类名。
成员变量和局部变量的区别在哪里
1.从语法上:
成员变量:定义在类内,可以被public,private,protected,static等修饰符修饰。
局部变量:定义在代码块或者方法内,不可以被除了final以外的修饰符修饰。
2.从内存上:
成员变量:如果成员变量是被static修饰的,那么这个成员变量是属于类的,如果被别的修饰符修饰,这个成员变量是属于对象的。对象被存储在堆内存中。
局部变量:局部变量被存储在栈内存中。
3.从生存时间上:
成员变量:成员变量是属于对象的,和对象同生死。
局部变量:局部变量在他所在的函数或者代码块执行完毕后自动死亡。
4.从初值上:
成员变量:成员变量如果没有被赋予初值,那么会自动被赋予相对应的基本数据类型的初始值。
局部变量:局部变量不会被自动赋值。
一种情况例外:被 final 修饰的成员变量也必须显式地赋值
创建一个对象用什么运算符,对象实体和对象引用有什么区别
创建对象用new运算符,新建对象实例。一个实例对象可以被无数个引用对象引用。一个引用对象只能同时引用0或1个实例对象。
构造方法有哪些特性
1.构造方法没有返回值,也不能用void修饰
2.名字必须与类同名,可以重载。
3.构造方法在创建对象实例时调用
在调用子类构造函数前会调用父类构造函数的原因?
子类继承父类的部分内容,构造父类的原因是要为子类的一系列活动做铺垫,帮助子类做初始化工作。
为什么要在java中定义一个什么都不做的构造函数?
我们通常会自己写一个构造函数,当我们写了构造函数以后,java就不会为类创造一个无参构造函数了。
但是,当我们写一个子类继承这个父类的时候,如果没有用super(....)调用父类的构造方式的话,java会自动调用父类的无参构造函数。但是我们已经写了一个构造函数了,此时子类如果不写super(....),java就找不到一个父类的无参构造函数了,于是程序编译出错。为了避免这种错误,我们就敬长在类中定义一个什么都不做的构造函数。
面向对象的三大特征
封装
封装指的是将一个对象的属性隐藏在类的内部(设置为private),不允许外部访问,但是可以提供一些外部方法来获取到属性。就像我们看不见钟表中的零件,但是我们可以通过旋转按钮来操控钟表变化。
如果属性不想被外部信息访问,我们大可不必提供方法给外界,当然,一个类如果没有提供任何给外界访问自身属性的方法,这个类是无意义的。
继承
继承指的是不同的类,有着许多相同的方法和属性,为了提高代码维护性和简洁性,使用一种拥有这些相同的方法和属性基础类作为父类来供他们继承的一种手段。子类的定义可以增加新的属性和新的功能,也可以使用父类的方法,但不能选择性地继承父类。继承有利于代码的重用性和可维护性,提高效率。
关于继承有以下三点
1.子类拥有父类的一切方法和属性,包括私有属性和方法,但是子类不能访问它们,只是拥有
2.子类可以在父类的基础上进行扩展,增加属性和方法
3.子类可以通过自己重新实现父类的一些方法
多态
例子和代码参考@程序狗 在知乎 ”JAVA的多态用几句话能直观地解释一下吗“ 下的回答https://www.zhihu.com/question/30082151/answer/120520568
下面先贴上两个代码来展示一下多态的使用
1 package test1; 2 3 public class Animal{ 4 public int age; 5 public Animal(int a) { 6 age=a; 7 } 8 public void sleep() { 9 System.out.println("动物睡觉"); 10 } 11 public static void eat() { 12 System.out.println("动物吃饭"); 13 } 14 }
1 package test1; 2 3 public class Cat extends Animal{ 4 public int age; 5 public Cat(int a) { 6 super(a); 7 } 8 public void sleep() { 9 System.out.println("猫猫睡觉"); 10 } 11 public static void eat() { 12 System.out.println("猫猫吃饭"); 13 } 14 public void catchmouth() { 15 System.out.println("猫猫抓老鼠"); 16 } 17 18 }
1 package test1; 2 3 public class test { 4 5 public static void main(String[] args) { 6 Animal a=new Cat(10);//新建一个10岁的猫,但是用animal指向它 7 a.sleep(); 8 a.eat(); 9 //a.catchmouth(); 10 11 } 12 13 }
解释一下,在动物类(父类)中,我们定义两个函数,一个是睡觉函数,另一个是吃饭函数,其中吃饭函数是一个静态方法。
在猫猫类(子类)中,我们定义三个函数,分别是两个继承来的函数,另一个是自己独有的抓老鼠的函数。
现在,我们在主函数中,新建一个猫猫,但是用动物指向它。即,在堆中创建一个猫猫,在栈中用动物指向这个猫猫。
这就是一个非常典型的多态。多态需要符合三个条件
1.存在继承关系
2.子类要重写父类的方法
3.父类数据类型的引用指向子类的对象
现在看一下结果:
解释一下这个结果:对于基本的函数,调用的是猫猫的函数,对于静态函数,调用的是动物的函数
什么意思呢?就是基本函数,编译看左边,运行看右边,动态绑定。对于静态函数,编译看左边,运行看右边。
那么多态的缺点是什么呢?就是不能使用子类中独有的函数和变量。
那么怎么解决这一问题呢?
1 package test1; 2 3 public class test { 4 5 public static void main(String[] args) { 6 Animal a=new Cat(10);//新建一个10岁的猫,但是用animal指向它 7 a.sleep(); 8 a.eat(); 9 //a.catchmouth(); 10 Cat b=(Cat) a; 11 b.catchmice(); 12 } 13 14 }
只需要把它再强制转换成子类就可以了。
修饰符
静态方法和实例方法有什么区别
1.在外部调用静态方法的时候可以使用 类名.静态方法 的方式调用,也可以用 对象.方法 调用。而实例方法只能用 对象.方法调用。也就是说调用静态方法不需要创建一个类。
2.静态方法在访问本类成员时只允许访问静态成员,不能访问实例成员和方法。实例方法则没有这个限制
为什么静态方法不能调用非静态成员
因为静态方法可以通过 类名.静态方法 的方式调用,调用静态方法可以不必创建实例,但是非静态成员一定是隶属于一个实例的,所以如果静态方法可以调用非静态成员就会出现错误,所以静态方法调用非静态成员是非法的。