java 面向对象面试集锦
java 面向对象:这里整理了面向对象的基础知识,帮助大家学习理解,希望能帮助到大家,这里是根据公司面试资料整理的相关知识:
Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
Overload是重载的意思,Override是覆盖的意思,也就是重写。重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
overload可以翻译为重载,是指定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
如果几个Overloaded的方法的参数列表不一样,它们的返回者类型可以不一样。如果两个方法的参数列表完全一样,就不可以通过返回值不同来实现重载Overload。我们可以用反证法来说明这个问题,例如,我们调用map.remove(key)方法时,虽然remove方法有返回值,但是我们通常都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,Java就无法确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。
构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concreteclass)?抽象类中是否可以有静态的main方法?
接口可以继承接口。抽象类可以实现(implements)接口。抽象类中可以有静态的main方法。
抽象类与普通类的唯一区别就是不能创建实例对象和允许有abstract方法。
写clone()方法时,通常都有一行代码,是什么?
Clone()方法就是克隆,就是拷贝对象;即已经有对象A,其中A中包含了一些有效的值,但想要有个对象B,并且对B的任何改动都不会影响到A中的值,但B又不是被new出的新的对象。
拷贝:①拷贝对象返回的是一个新的对象,而不是有一个引用。②拷贝对象与用new操作符返回的对象的区别是拷贝的已经包含了原来对象的信息,而不是对象的初始信息
clone有缺省行为,super.clone();因为首先要把父类中的成员复制到位,然后才是复制自己的成员。
面向对象的特征有哪些方面
面向对象的编程语言有封装、继承、抽象、多态等4个主要的特征。
1封装:
封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装。把握一个原则:把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中。
2.抽象:
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,如下:
classPerson{ Stringname; intage; }
人本来是很复杂的事物,有很多方面,但因为当前系统只需要了解人的姓名和年龄,所以上面定义的类中只包含姓名和年龄这两个属性,这就是一种抽像,使用抽象可以避免考虑一些与目标无关的细节。
3.继承:
在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
4多态:
多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态性增强了软件的灵活性和扩展性。例如,下面代码中的UserDao是一个接口,它定义引用变量userDao指向的实例对象由daofactory.getDao()在执行的时候返回,有时候指向的是UserJdbcDao这个实现,有时候指向的是UserHibernateDao这个实现,这样,不用修改源代码,就可以改变userDao指向的具体类实现,从而导致userDao.insertUser()方法调用的具体代码也随之改变,即有时候调用的是UserJdbcDao的insertUser方法,有时候调用的是UserHibernateDao的insertUser方法:
UserDaouserDao=daofactory.getDao();userDao.insertUser(user);
java中实现多态的机制是什么?
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
abstractclass和interface有什么区别?
含有abstract修饰符的class即为抽象类,abstract类不能创建的实例对象。含有abstract方法的类必须定义为abstractclass,abstractclass类中的方法不必是抽象的。abstractclass类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为publicabstract类型,接口中的成员变量类型默认为publicstaticfinal。
两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4.抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为publicabstract类型。
5.抽象类中可以包含静态方法,接口中不能包含静态方法
6.抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是publicstaticfinal类型,并且默认即为publicstaticfinal类型。
7.一个类可以实现多个接口,但只能继承一个抽象类。
两者在应用上的区别:
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码,伪代码如下:
publicabstractclassBaseServletextendsHttpServlet{ publicfinalvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throws IOExcetion,ServletException{ 记录访问日志 进行权限判断 if(具有权限){ try{ doService(request,response); } catch(Excetpione){ 记录异常信息 } } } protectedabstractvoiddoService(HttpServletRequestrequest,HttpServletResponseresponse)throws IOExcetion,ServletException;//注意访问权限定义成protected,显得既专业,又严谨,因为它是} 专门给子类用的 publicclassMyServlet1extendsBaseServlet { protectedvoiddoService(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOExcetion,ServletException { 本Servlet只处理的具体业务逻辑代码 } }
父类方法中间的某段代码不确定,留给子类干,就用模板方法设计模式。
abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
abstract的method不可以是static的,因为抽象的方法是要被子类实现的,而static与子类扯不上关系!
native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与abstract混用。例如,FileOutputSteam类要硬件打交道,底层的实现用的是操作系统相关的api实现,例如,在windows用C语言实现的,所以,查看jdk的源代码,可以发现FileOutputStream的open方法的定义如下:privatenativevoidopen(Stringname)throwsFileNotFoundException;
如果我们要用java调用别人写的c语言函数,我们是无法直接调用的,我们需要按照java的要求写一个c语言的函数,又我们的这个c语言函数去调用别人的c语言函数。由于我们的c语言函数是按java的要求来写的,我们这个c语言函数就可以与java对接上,java那边的对接方式就是定义出与我们这个c函数相对应的方法,java中对应的方法不需要写具体的代码,但需要在前面声明native。
对于synchronized,方法上的synchronized同步所使用的同步锁对象是this,而抽象方法上无法确定this是什么。
什么是内部类?StaticNestedClass和InnerClass的不同。
内部类就是在一个类的内部定义的类,内部类中不能定义静态成员,静态成员不是对象的特性,只是为了找一个容身之处,所以需要放到一个类中而已,,内部类可以直接访问外部类中的成员变量,内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中,如下所示:
publicclassOuter { intout_x=0; publicvoidmethod() { Inner1inner1=newInner1(); publicclassInner2//在方法体内部定义的内部类 { publicmethod() { out_x=3; } } Inner2inner2=newInner2(); } publicclassInner1//在方法体外面定义的内部类 { } }
在方法体外面定义的内部类的访问类型可以是public,protecte,默认的private等4种类型,这就好像类中定义的成员变量有4种访问类型一样,它们决定这个内部类的定义对其他类是否可见;对于这种情况,我们也可以在外面创建内部类的实例对象,创建内部类的实例对象时,一定要先创建外部类的实例对象,然后用这个外部类的实例对象去创建内部类的实例对象,代码如下:
Outerouter=newOuter();
Outer.Inner1inner1=outer.newInnner1();
在方法内部定义的内部类前面不能有访问类型修饰符,就好像方法中定义的局部变量一样,但这种内部类的前面可以使用final或abstract修饰符。这种内部类对其他类是不可见的其他类无法引用这种内部类,但是这种内部类创建的实例对象可以传递给其他类访问。这种内部类必须是先定义,后使用,即内部类的定义代码必须出现在使用该类之前,这与方法中的局部变量必须先定义后使用的道理也是一样的。这种内部类可以访问方法体中的局部变量,但是,该局部变量前必须加final修饰符。
在方法体内部还可以采用如下语法来创建一种匿名内部类,即定义某一接口或类的子类的同时,还创建了该子类的实例对象,无需为该子类定义名称:
publicclassOuter { publicvoidstart() { newThread( newRunable(){ publicvoidrun(){}; }).start(); } }
最后,在方法外部定义的内部类前面可以加上static关键字,从而成为StaticNestedClass,它不再具有内部类的特性,所有,从狭义上讲,它不是内部类。StaticNestedClass与普通类在运行时的行为和功能上没有什么区别,只是在编程引用时的语法上有一些差别,它可以定义成public、protected、默认的、private等多种类型,而普通类只能定义成public和默认的这两种类型。在外面引用StaticNestedClass类的名称为“外部类名.内部类名”。在外面不需要创建外部类的实例对象,就可以直接创建StaticNestedClass,例如,假设Inner是定义在Outer类中的StaticNestedClass,那么可以使用如下语句创建Inner类:
Outer.Innerinner=newOuter.Inner();
由于staticNestedClass不依赖于外部类的实例对象,所以,staticNestedClass能访问外部类的非static成员变量。当在外部类中访问StaticNestedClass时,可以直接使用StaticNestedClass的名字,而不需要加上外部类的名字了,在StaticNestedClass中也可以直接引用外部类的static的成员变量,不需要加上外部类的名字。
在静态方法中定义的内部类也是StaticNestedClass,这时候不能在类前面加static关键字,静态方法中的StaticNestedClass与普通方法中的内部类的应用方式很相似,它除了可以直接访问外部类中的static的成员变量,还可以访问静态方法中的局部变量,但是,该局部变量前必须加final修饰符。
内部类可以引用它的包含类的成员吗?有没有什么限制?
完全可以。如果不是静态内部类,就没有什么限制!
如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员,例如,下面的代码:
classOuter { staticintx; staticclassInner { voidtest() { syso(x); } } } }
AnonymousInnerClass(匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
可以继承其他类或实现其他接口。不仅是可以,而是必须!
例如:
importjava.util.Date; publicclassTestextendsDate{ publicstaticvoidmain(String[]args){ newTest().test(); } publicvoidtest(){ System.out.println(super.getClass().getName()); } }
结果是Test
在test方法中,直接调用getClass().getName()方法,返回的是Test类名,由于getClass()在Object类中定义成了final,子类不能覆盖该方法,所以,在test方法中调用getClass().getName()方法,其实就是在调用从父类继承的getClass()方法,等效于调用super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也应该是Test。如果想得到父类的名称,应该用如下代码:
getClass().getSuperClass().getName();
面向对象与面向过程有什么区别
1出发点不同。面向对象方法是用符合常规思维的方式来处理客观世界的问题。强调把问题域的要领直接影射到对象与对象之间的接口上。而面向过程方法强调的则是过程的抽象化与模块化,它是以过程为中心构造或处理客观世界问题。
2层次逻辑不同,面向对象方法是用计算机逻辑来模拟客观世界中的物理存在,以对象的集合类作为处理问题的基本单位,尽可能使计算机世界像客观世界靠拢,以使问题的处理更加直接清晰直接,面向对象方法是用类的层次结构来体现类之间的继承与发展,而面向对象过程方法处理问题的基本单位使能清晰准确的表达过程的模块,用模块的层次结构概括模块或模块间的关系与功能,把客观世界的问题抽象成计算机可以处理的过程
3数据处理方式与控制程序方式不同。面向对象方法将数据与对应的代码封装成一个整体,原则上其他对象不能直接修改其数据,即对象的修改只能由自身的成员函数完成,控制程序方式上是通过“事件驱动”来激活和运行程序。而面向对象过程是直接通过程序来处理数据,处理完毕后即显示处理结果,在控制程序方式上是按照设计调用或返回程序,不能由导航,各模块之间存在控制与被控制,调用与被调用的关系。
4分析设计与编码转换方式不同。面向对象方法贯穿于软件生命周期的分析。设计及编码中,是一个平滑的过程,从分析到设计再到编码是采用一致性的模型展示,即实现的是一种无缝连接。而面向对象过程方法强调分析设计以及编码之间按规则进行转换,贯穿与软件生命周期的分析,设计及编码中,实现的是一种有缝连接。
面向对象开发方式有什么优点
1较高的开发效率。采用面向对象开发,可以对现实的事物进行抽象,可以把现实的实务直接映射为开发的对象。
2保证软件的鲁棒性,正是由于面向对象开发方法有很高的重用性,在开发过程中可以重用已有的而且在相关领域经过长期测试的代码,因此,自然而然的对软件的鲁棒性起到很好的促进作用。
3保证软件的高维护性。由于采用面向对象的开发方式,使得代码的可读性非常好,同时面向对象的设计模式使得代码结构更加清晰明了,同时针对面向对象开发模式,已有许多非常成熟的设计模式,这些设计模式可以使程序在面对需求的变更时,只需要修改部分的模块就可以满足需求,因为维护起来更加方便。
This与super有什么区别
在JAVA语言中,this是指向当前实例对象,他的一个非常重要的作用就是用来区分对象的成员变量与方法的形参(当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量)。
Super可以用来访问父类的方法或成员变量。当子类的方法或成员变量与父类有相同的名字时也会覆盖父类的方法或成员变量,要想访问父类的方法或成员变量只能通过super关键字来访问
如何获取父类的类名
Java语言中提供了获取类名的方法:getClass().getName(),开发人员可以调用这个方法来获取类名。但对于继承,不能通过调用父类的getClass().getName()方法来获取父类的类名例如:
ClassA{} PublicclassTestextendsA{ publicvoidtest(){ System.out.println(super.getClass().getName()); } Publicstaticvoidmain(String[])args){ NewTest.test(); } }
程序运行结果为Test。原因是java语言中任何类都继承自object类,getClass方法在object类中被定义为final何native,子类不能覆盖该方法。因此this.getClass()和super.getClass()最终都调用的object类中的getClass()方法.而object类中的getClass()方法的释义是:返回此object的运行时类。可以通过java的反射机制在子类中获取父类的名字代码如下:
ClassA{} PublicclassTestextendsA{ publicvoidtest(){ System.out.println(this.getClass().getSuperclass().getName()); } Publcistaticvoidmain(string[]args){ NewTest().test(); } }
组合与继承有什么区别
组合和继承是面向对象中两种代码复用的方式。组合是指在新类里面创建原有类的对象,重复利用已有类的功能。继承是面向对象的主要特性之一,它允许设计人员根据其他类的实现来定义一个类的实现。组合和继承都允许在新的类中设置子对象,只是组合是显示的,而继承是隐式的。组合和继承存在着对应关系:组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应。在使用时遵循以下两点原则:
1除非两个类之间是“is-a”的关系,否则不要轻易使用继承,因为过多的使用继承会破坏代码的可维护性,当父类被修改时,会影响到所有继承自他的子类。
2,不要仅仅为了实现多态而使用继承,如果类之间不是“is-a”的关系,就可以通过实现接口与组合的方式来达到相同的目的。
由于java语言只支持单继承,如果想同时继承两个或多个类,在Java中是无法直接实现的,同时,在java语言中,如果继承太多,也会使一个class里面的内容变得臃肿不堪,所以在Java语言中,能使用组合就尽量不使用继承。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!