黑马程序员技术交流社区

标题: java 面试必考的理论题 [打印本页]

作者: 工善器    时间: 2013-10-27 10:11
标题: java 面试必考的理论题
本帖最后由 工善器 于 2013-10-27 11:04 编辑

大家都谈谈谈面试必考的理论知识点,非操作类的,我会跟进这个帖子 ,大家也积极发言啂(一定要非常通俗易懂。或者很经典,不过在我心中,经典的都是最通俗易懂的。)
可以提一个知识点,比如某个知识点觉得是可定要考的,都可以提(但是不要太大,就二楼一样),也可以详细解释某个知识点


作者: 工善器    时间: 2013-10-27 10:14
难道是??
第一部分:
java编程基础:
变量、数据类型、运算符、流控语句(if、switch、for、while)、枚举、数组、函数、变量作用域、变量与变量的值、字符串的内存管理、字符串的处理。   
第二部分:
java面向对象基础:
类、成员访问级别、属性、方法、值类型与引用类型、构造函数、继承、类型转换、接口、多态、泛型、异常、常量、static、命名空间。                           
第三部分:HTML基本知识:
基本标签(a、p、img、li、table、div、span)、表单标签、iframe、frameset、样式  

作者: 工善器    时间: 2013-10-27 10:21
本帖最后由 工善器 于 2013-10-28 20:07 编辑

问题一,到底是声明的是变量还是引用(这个是最最基本和最最容易忽略的问题)
比如下面的代码:
    String s = "Hello world!";  

许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个String(一个字符串变量),内容是“Hello world!”。这样模糊的回答通常是概念不清的根源。如果要准确的回答,一半的人大概会回答错误。

这个语句其实声明的是一个指向对象的引用,名为“s”,可以指向类型为String的任何对象,目前指向"Hello world!" 这个String类型的对象。这就是真正发生的事情。我们并没有声明一个String对象,我们只是声明了一个只能指向String对象的引用变量。(注意是“引用的”的变量)
所以,如果在刚才那句语句后面,如果再运行一句:

    String string = s;  

我们是声明了另外一个只能指向String对象的引用,名为string,并没有第二个对象产生,string还是指向原来那个对象,也就是,和s指向同一个对象---”hello world”
作者: 工善器    时间: 2013-10-27 10:22
这个问题我认为是最经典的问题,也是面试者,必须掌握的基础知识点,可能不会特别被问到,但是相关的概念是,入学新生必须理解的。我会继续更新
作者: 工善器    时间: 2013-10-27 10:57
面向对象三原理:
第一:多态
多态是java的一个很重要的部分,就是一个方法名多次使用(不同与简单的方法多次调用),具体根据参数的不同来分辨你调用哪个方法,通俗的解释多态就是,假如有个方法名叫:“动物的叫声”
那么,当你传递的参数是动物狗,则调用狗叫声,是猫,则调用猫叫声,这就是多态。这个描述应该是最好理解的了
传递的参数是对象,传进去那个对象,就执行对象的响应的功能。这个功能根据那个方法确定,但是效果却不同。
也就是指允许不同类的对象对同一消息作出响应。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
多态有两种表现形式:重载和覆盖
1.首先说重载(overload)
要求发生在同一类中。  
  在以前的学习中我们知道,标识一个函数除了函数名外,还有函数的参数(个数和类型)。也就是说存在这样的情况:(一个类中)可以有两个或更多的函数,叫同一个名字而他们的参数不同。   
  根据函数的定义(相同的1.函数名和相同的2.参数列表和相同的3.返回值类型才表明函数是相同的)他们是不同的函数,只是可能他们的功能类似,所以才命名一样,增加可读性
   
  2、覆盖(override),必须有继承的情况下才有覆盖发生,覆盖的执行者是子类。

  当一个类(我们叫他子类)继承了另一个类(我们叫他父类)之后,他就具有了父类的全部方法。如果只是单纯的继承,那我们其实是在复制一个一个的父类,这是没有意义的。所以子类继承父类后,必须重写父类的方法。方法在父类中可能只是一个雏形,一个框架,真正在功能实现中大显身手的是子类重写后的方法,当我们调用这样的方法的时候,就是在执行子类的过程,父类的方法就被覆盖了。
注意:覆盖的时候函数名和参数要和父类中完全一样,不然你的方法对父类中的方法就不起任何作用,因为两者是两个函数,毫无关系。
作者: 工善器    时间: 2013-10-28 19:04
封装在我心目中是最神圣的东西。。(呵呵勿喷),原因是在可见世界中,所有对象自然携带有封装的性质。比如人是一个对象(错误?人是一个类,罪过),我是一个对象,我的笔记本是一个对象,在现实世界中,他们都是被封装过的(都是封装体)。比如我身上穿有衣服,寒冷,呀,沙尘呀,只能访问我的裸露的手部脸部。其他部位是不能访问到的。笔记本只能通过键盘鼠标访问到(但是现在一些笔记本可以通过屏幕访问,触控屏,有新增了接口),他外边有厚厚的壳儿。封装已进入哲学的概念。
        这个东西不能讲太多,老师问的时候也就是个大概,下面通过设计类来谈
Java封装中,最常见的一种形式是对变量的封装。在编码中我们极易用错变量。原因有以下两点,一,变量直接被赋予了值或引用,我们写上名字,变量中的内容就会传递过来,中间没有什么逻辑关系。二,在编码中,变量的数目是惊人的,他们被我们定义,很可能有重名的时候。三,有些变量是某些方法或类不想让另一个类或方法看到的,他们想单独拥有一些自己的变量。
具体实现方法是:定义一个变量,设置为private(代表只能私有访问),再定义一个专门的函数访问这个变量,或为变量赋值,等等。所有对这个变量的使用都被详细分工,他们或访问,或赋值,一切有序进行。再不能直接使用。可以想见他克服了以上提出的三个问题
类的设计应该考虑到视为不同用户使用。为了能够在较大应用范围内生效,类应该通过属性和方法提供多种方法实现自定义。
类的设计应该考虑到重用。用户能够通过不同的组合,顺序和环境来合并类。因此,你设计的类应该是无论用户做什么,何时做,都能够无限制的的使用。设计的属性应该是可以让用户任意顺序的排放,设计的值任意合并;设计的方法,她的功能不依赖于他们 出现的顺序。
只要有可能,就提供共有的默认构造函数,重写equals 方法和定义在object类中的头string 方法。
遵守标准的java编程风格和命名规则。类,数据域和方法应该选择有提示性的名称,把数据声明放在构造函数之前,构造函数放在方法之前。
作者: 工善器    时间: 2013-10-28 19:08
中间部分的衔接,我为什么通过设计类来谈封装,中间却一句话,封装的主要体现形式,就是类,每一个类就是一个封装体。这样启承更流畅
作者: 工善器    时间: 2013-10-28 19:32
继承和组合
一般来讲,继承和组合的差别就是is a 和has a 的关系的差别。例如,苹果是水果,你应该使用继承来建立类apple 和fruit 的关系模型。人有名字,因而你应该使用组合来建立person和那么的关系模型。有时候继承和组合的选择不是很明确。这是我想起uml (大三的课,不知道众位计算机系的学过没,有的学校没有)中的一句话,好的类设计,就像是一篮子鸡蛋,清清爽爽,差的设计就像是打碎的鸡蛋,黏黏糊糊。还有毕老师的经典,人开门。开的动作可以是人发出的,也可以是门发出的,如果开这个动作在门中的多,就涉及到门里面去,如果是人的多,就设计到人里面去,我们普遍认可后者---人,但这可能是一个误解,其实真正开的是门。 开属于门的部分更多,人开只是一个触发条件。毕老师在无形中回答了如何设计类这个颇高深的命题。那么回到刚才的那句话,在这里开设计到门里就叫清爽,设计到人里其实就是含糊,或者说是对现实世界的描述,不佳。这就像,组合和继承,有些情况看起来都可以,但是究竟更偏向于谁呢,这使我们值得考虑和设计的地方。
以上是在描述世界的恰当性上来讲(艺术领域),实际中操作中并未如此复杂(技术领域),如果想要使用多态性,那么使用继承设计。如果不使用多态性,那么使用组合要比使用继承好,组合设计具有更多的灵活性,因为类之间的依赖性减少。
作者: 工善器    时间: 2013-10-28 19:44
本帖最后由 工善器 于 2013-10-28 20:10 编辑

接口和抽象类
接口和抽象类都尅用来概括共同特性。那么怎样决定是使用接口还是设计类呢?大体上讲,清楚地描述负责关系的强 is a 关系用类来建立关系模型。例如橘子是水果,他们的关系应该使用类继承来建立关系模型。弱is a 关系,又叫做 is kind of 关系,说明对象具有一定的属性。弱is a 关系使用接口来建立关系模型。
一句话:继承抽象类用来说明本质,接口只是描述类的一个功能。
继承和组合的抉择我们看重他们的本质区别。接口和抽象类的设计我们要把重心放到实际运用上。
接口比抽象类在使用上,更灵活。因为子类只能扩充一个超类,但是可以实现任意数量的接口。然而,接口不能包含具体的方法,通过创建接口并且具有能够实现它的同组的抽象类,将接口和抽象类的优点合并起来,然后捏可以使用接口或者他同组的类,无论哪个都很方便。
作者: 工善器    时间: 2013-10-28 20:00
本帖最后由 工善器 于 2013-11-6 09:12 编辑

问题:由一个 string的问题讨论理解一个内存开销问题(说实话我一直对内存开销理解不怎么样,这是我唯一理解的内存开销问题,也是我觉得最基本的要理解的问题,至于类的设计在栈,对象在堆内存,这个是内存位置问题,不是内存开销,以后会撰文,这个也是非常基本的)
我们知道在java中,String被设计成不可变(immutable)类,它的所有对象都是不可变对象。请看下列代码:
String s = "Hello";  
s = s + " world!";  
s 所指向的对象是否改变了呢?从本系列第一篇的结论(指向对象和指向引用问题)很容易导出这个结论。我们来看看发生了什么事情。在这段代码中,s原先指向一个String对象,内容 是"Hello",然后我们对s进行了+操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个 String对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。
通 过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很 大的内存开销。因为String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用 StringBuffer类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。
同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都new一个String。例如我们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样做:
public class Demo {  
private String s;  
...  
public Demo {  
s = "Initial Value";  
}  
...  
}
而非
s = new String("Initial Value");
后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为String对象不可改变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的String类型属性s都指向同一个对象。
上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。
至 于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候, 我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不 会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即 StringBuffer。




EG:再附上一个例子
package it.cast.java.util;

public class StringDemo{
    public static void main(String[] args)
    {
        //其实“”表示的是String的匿名对象
        String s="";
        /*
         * String() 初始化一个新创建的string对象,使其表示一个空字符串序列
         * “”不是表示null
         * String (String original)
         * String s=new String("asd");
         *s的值就是asd
         
         * */
        s=new String();
        //s=""
        String s1=new String("11");
        String s2=new String("11");
        System.out.println(s1==s2);
        String s3="22";
        String s4="22";
        System.out.println(s3==s4);
        System.out.println(s3==s2);
        String s5="2"+"2";
        //这句话其实在编译器编译后的class文件中,已经变成“22”;
        //当然这没有太大的意义,平时也不这样写
        //s5创建了几个对象, 最多一个,如果常量池里面没有就是创建一个,如果常量池
        //本来就有不创建。下面的str也是一样
        String str="A"+"B"+"C"+"D"+"E";
        System.out.println(s3==s5);//结果为真,就是刚才说的那句话,没创建
        /*
         * String的特点:不可变,一个string对象的内容不能变,一旦内容变,该对象就变成
         * 一个新的String对象了
         
         */
        String str1="ABCDE";
        System.out.println(str==str1);//true
        String str2="ABC"+"DE";
        System.out.println(str==str2);//true
        String ss="AB";
        String str3=ss+"CDE";//在运行期间才能确定str3的值
        System.out.println(str3==str2);
        String str4=getStr()+"CDE";//在运行期间才能确定str4的值
        System.out.println(str==str4);
        System.out.println(str3==str4);        
    }
    public static String getStr(){
        return "AB";
    }
}

作者: 工善器    时间: 2013-10-28 20:04
工善器 发表于 2013-10-28 19:44
接口和抽象类
接口和抽象类都尅用来概括共同特性。那么怎样决定是使用接口还是设计类呢?大体上讲,清楚地 ...

写完这个后 ,我他妈的感觉我就是个天才,:curse:可以出书了,系列更新,欢迎大家批评。指正,我会修改的,我另存的一份word 打印自己看。
作者: 姚团结    时间: 2013-10-28 22:09
很好,十分感谢!一些东西讲的通俗易懂还很有趣
作者: 工善器    时间: 2013-10-29 15:48
谢谢支持
作者: 工善器    时间: 2013-10-29 16:16
抽象类和抽象方法(如果我写的这些东西你有什么不理解的可以说,会改,保证的是绝对好理解,提高面试信心)
在Java中被abstract修饰的类,叫抽象类,被abstract修饰的方法,叫抽象方法。
抽象类和抽象方法原则:
(1)抽象类必须使用abstract修饰符修饰,抽象方法必须使用abstract修饰符修饰,抽象方法不能有方法体。
(2)抽象类不能被实例化,即使抽象类中不包含抽象方法,同样也不能创建实例。
(3)抽象类可以包含属性,方法(普通方法和抽象方法都可以),构造器,初始化块,内部类,枚举类六种成分。抽象类的构造器不能用于创建实例,主要是用于被子类调用。
(4)含有抽象方法的类,只能被定义为抽象类。

注意:
(1)抽象方法和空方法体的方法是不同概念,例如public abstract void test();是一个抽象方法,它根本没有方法体,方法后面没有大括号,但public void test(){}方法是一个普通的方法,他已经定义了方法体,只是方法体是空,因此该方法不能用abstract修饰。
(2)abstract不能用于修饰属性,不能用于修饰局部变量,即使没有抽象变量,没有抽象属性等说法;abstract也不能修饰构造器,没有抽象构造器。抽象类中定义的构造器只能是普通的构造器。
(3)static和abstract不能同时修饰某个方法。
当使用static修饰一个方法时,该方法属于类,如果该方法为抽象方法,则将导致通过该类来调用该方法时出现错误,抽象方式哪里能类调用?因此static和abstract不能同时修饰某个方法。
static 方法是类方法,它是不允许子类覆写(override)而abstract方法是没有实现的方法,是必须由子类来覆写的。
因此也发生矛盾

(4)abstract关键字修饰的方法必须被子类重写才有意义,因此abstract方法不能定义为private访问权限。

抽象类的作用:
抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模版,从而避免子类 设计的随意性。抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展,改造,但子类总体上会大致保留抽象类 的行为方式。
作者: 从前有个人    时间: 2013-10-31 02:12
好东西,非常感谢。
作者: FFF    时间: 2013-10-31 19:54
为什么不更新了呢???说她的承诺呢?
作者: 工善器    时间: 2013-11-1 07:43
呵呵,本人基础加强中,没有自己的理解,不会再写的,要是把别人的全篇粘过来就没意思了
作者: FFF    时间: 2013-11-1 08:43
楼主视频看到几天了?
作者: 工善器    时间: 2013-11-1 09:18
这个,说说我现在的体会,视频,我是看的差不多了,但是,中间过程中 由于本人毅力问题,(我相信大多数人都会如此,看完了视频,对着可能不好敲代码,就放弃来了,或者对着敲了一遍,不是自己想着敲了一遍,过后又没有总结),并没有完全把知识点消化,略懂,似懂非懂 ,或者看完了一遍,没有及时反过来再看一遍。(光看,一遍也是不行的),所以要勤敲代码。,全都多敲几遍,从头到尾。一定收获非常
作者: 工善器    时间: 2013-11-1 09:19
忘了你是四十八分了,还以为你刚要 开始,哈哈,献丑了
作者: 工善器    时间: 2013-11-2 08:36
课程大纲

        第一天(2013年10月22日  20:30-22:30):基础知识
Eclipse高级应用(做过几年的老鸟也未必知道)
面试必考知识点(String、正则表达式)

第二天(2013年10月24日  20:30-22:30):线程
多种开启线程的方式及原理
多种同步、通信方式的区别及利弊

第三天(2013年10月26日  20:30-22:30):集合
Collection详解(List和Set的区别和不同)
Map详解(各种Map的应用场景)

第四天(2013年10月28日  20:30-22:30):IO
字节流和字符流究竟怎么用
File类以及文件夹递归

第五天(2013年10月30日  20:30-22:30):网络编程
UDP群发数据、TCP多线程服务器
黑马相关问题答疑互动
作者: ☆星痕泪    时间: 2013-11-2 15:30
收藏了!希望楼主持续更新啊,在19楼说的很对,感觉一直困在一个知识点,总感觉放不开,所以我也是尽量看懂每天每节的视频并亲手敲上一遍,不懂的现在也没太非要纠结,到学习后面某个知识点时你可能一下就明白了。最后毅力是一方面,没有系统回顾复习也是学习的模模糊糊的主因,等学习完25天课程再回头知识点 的复习应该会感觉好很多。现在GUI学习,加油!
作者: 工善器    时间: 2013-11-3 17:13
黑马说要考string的,这个string怎么考嫩??不知道,今天随便写一段
一个String对象的长度是固定的,你不能过分改变它的内容,比如,增加长度到过长,或者是附加新的字符至String对象中。
您也许会使用+来串联字符串以达到附加新字符或字符串的目的,但+会产生一个新的String实例。
如果程序对这种附加字符串的需求很频繁,那你就更不能这样做了,算算你产生了多少string吧。
对象的生成需要内存空间与时间,不断地产生String实例是一个没有效率的行为,讲究高效的java肯定不会只有一个string来抵挡这样的问题,
我们最好是能重复运用一个对象,StringBuilder 和Stringbuffer 应运而生。
stringBuilder很不错的,完全可以替代string,最主要的是它的效率高

//必须先实例化一个
stringBuilder sBuilder = new stringBuilder();
//StringBuilder它可以自由拼接易于阅读。
例如,执行SQL语句:
sBuilder.Append("select * from tb1");
sBuilder.Append("where id=1");

因为是自由拼接,所以上面同等于:
strng sBuilder = "select * from tb1 where id=1";
StringBuilder 受到欢迎,还因为它能在string 字符串,数组,之间来回转换游刃有余。
比如传智的经典例题:
package it.cast.java.util;
/*
使用StringBuilder或者StringBuffer;
将字符串“ABCDE”;
转变为“A,B,C,D”;
这是一个黑马的入学考试题,
*/
public class StringBuilder2{
        public static void main(String[] args)
        {
                //先把那个abcde写入到StringBuilder里面
               
                StringBuilder s=new StringBuilder("ABCDE");
                //删除掉那个多余的字符e
                s.deleteCharAt(4);
                /*将删除后的Stringbuilder类型 转换为string类型,
                我们当时为什么转换为Stringbuilder 类型,就是他接收方便,
                向String类型转换的时候方便。
                这里,将stringbuilder类型,转换为string类型,在数组排序。
                新建一个数组s1
                */
       
                char[] s1=s.toString().toCharArray();
                //再建一个stringbuilder 类型,用来接收排序好的数组,向Stringbuilder类型的转换
                StringBuilder ss=new StringBuilder();
                for(char c:s1){
                        ss.append(c).append(",");
                }
                //因为每一个字符后面都有一个逗号,而按题目要求,最后一个逗号是不能要的。
                ss.deleteCharAt(ss.length()-1);
                System.out.println(ss);
                //直接输出ss,就行了。
        }
}

J2SE   5.0提供java.lang.StringBuilder类,使用这个类所产生的对象默认会有16个字符的长度,您也可以自行指定初始长度。如果附加的字符超出可容纳的长度,则StringBuilder对象会自动增加长度以容纳被附加的字符。如果有频繁作字符串附加的需求,使用StringBuilder会让程序的效率大大提高。


作者: 工善器    时间: 2013-11-3 19:06
工善器 发表于 2013-11-3 17:13
黑马说要考string的,这个string怎么考嫩??不知道,今天随便写一段
一个String对象的长度是固定的,你不 ...

很意外,很惊喜,谢谢版主的技术分,哈哈哈




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2