疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java基础对象、集合


 

   

  二、面向对象

  1、对象存储到什么地方?

  寄存器。这是最快的存储区,寄存器的数量及其有限,由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何现象。

  栈。栈指针向下移动则分配新的内存,向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。基本数据类型和对象引用存储在其中。

  堆。一种通用性的内存池,用于存放所有的java对象,堆不同于栈的好处在于:编译器不需要知道从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多少时间。

  静态存储。静态存储里存放 程序运行时一直存放的数据。Static 关键字的对象存放在其中。static局部变量在所处模块在初次运行时进行初始化工作,且只操作一次。

  常量存储。常量值通常直接存放在程序代码内部,这样做是安全的,因为他们永远不会被 改变。

  非RAM存储。比如流对象和持久化对象,发送给另一台机器或者存放在磁盘上。

  2、基本成员默认值

  如果类的某个成员是基本数据类型,即使没有进行初始化,Java也会确保他获得一个默认值。

  boolean false

  char null

  byte 0

  short 0

  int 0

  long 0

  float 0.0

  double 0.0

  3、在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零。在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化—— 甚至在构建器调用之前。

  static 初始化只有在必要的时候才会进行。如果不创建一个 Table 对象,而且永远都不引用 Table.b1 或Table.b2,那么 static Bowl b1 和 b2 永远都不会创建。然而,只有在创建了第一个 Table 对象之后(或者发生了第一次 static 访问),它们才会创建。在那以后, static 对象不会重新初始化。初始化的顺序是首先 static(如果它们尚未由前一次对象创建过程初始化),接着是非static 对象

  4、类的设计中为什么要控制对成员的访问?

  1、防止用户接触那些他们不应碰的工具。对于数据类型的内部机制,那些工具是必需的。但它们并不属于用户接口的一部分,用户不必用它来解决自己的特定问题。比如private的方法,有些是不希望被用户使用的。

  2、允许类设计者改变类的内部工作机制,同时不必担心它会对客户程序员产生什么影响。

  3、防止类的成员被用户随意修改,比如用户通过 类名.成员名 就可以改变类的属性值。

  5、为什么优先使用组合而非继承?

  1、继承破坏封装性。基类的很多内部细节都是对派生类可见的,因此这种复用是“白箱复用”;

  2、如果基类的实现发生改变,那么派生类的实现也将随之改变。这样就导致了子类行为的不可预知性;

  3、组成不会强迫我们的程序设计进入继承的分级结构中。同时,组成显得更加灵活,因为可以动态选择一种类型(以及行为),而继承要求在编译期间准确地知道一种类型。因此降低了应用的灵活性。

  6、一条常规的设计准则是:用继承表达行为间的差异,并用成员变量表达状态的变化。

  7、为什么要向上转型?

  好处:向上转型主要是为了用变量来接收不同的子类对象,调用方法的时候传参父类对象,可以调用子类中不同的重写方法,实现不同的效果。

  坏处:屏蔽了子类中新增的变量和方法。

  8、static关键字 强调他们只有一个,而final 关键字强调他们是一个常数。不能由于某样东西的属性是final,就认定他的值在编译的时候已经知道,其实final的值是进行类对象初始化的时候确定的。

  9、final 关键字 修饰方法 的好处?

  1、为方法“上锁”,防止任何继承类改变它的本来含义。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。

  2、将一个方法设成 final 后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个 final 方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能受到到不到嵌入代码所带来的任何性能提升。因为任何提升都被花在方法内部的时间抵消了。 Java 编译器能自动侦测这些情况,并颇为“明智”地决定是否嵌入一个 final 方法。然而,最好还是不要完全相信编译器能正确地作出所有判断。通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。

  10、为什么要把方法定义成抽象或者定义接口?

  1、它能为不同的子类型或者实现类作出不同的表示。它为我们建立了一种基本形式,使我们能定义在所有衍生类里“通用”的一些东西。比如 子类继承了父类,虽然如果方法名与父类相同,但自变量或参数不同,就会出现重载现象,那或许并非我们所愿意的。所以好一点的方法,就是在父类或者接口中建立一种标准。

  2、还有就是父类中的方法实现其实很冗余,基本用不到

  11、接口也包含了基本数据类型的数据成员,但他们都默认是static 和 final,必须获得初始化(所以可以借助此性质定义需要的“枚举值”,通过接口名.变量名来访问)。接口只提供一种形式,并不提供实施的细节。

  12、接口当作方法的形参的时候,传入的不仅可以是接口的实现类,也可以是实现类的子类。

  13、利用继承技术,可方便地为一个接口添加新的方法声明,也可以将几个接口合并成一个新接口。在这两种情况下,最终都得到一个新接口。接口的继承实际上是一个接口功能增加的过程,有些应用只需要简单的接口。通过继承,可以在简单的接口上得到适合自己需要的复杂接口。

  14、可以在一个类的内部定义新的类,称为内部类,如果想生成内部类的一个对象,必须将那个对象的类型设为"外部类名.内部类名"

  15、为什么需要定义内部类?

  1、我们准备实现某种形式的接口,使自己能够创建和返回一个引用。

  2、要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。

  16、匿名内部类

  1、如果是接口,相当于在内部返回了一个接口的实现类,并且实现方式是在类的内部进行的;

  2、如果是普通类,匿名类相当于继承了父类,是一个子类,并可以重写父类的方法。

  3、需要特别注意的是,匿名类没有名字,不能拥有一个构造器。如果想为匿名类初始化,让匿名类获得一个初始化值,或者说,想使用匿名内部类外部的一个对象,则编译器要求外部对象为final属性,否则在运行期间会报错。

  复制代码

  public class Parcel8 {

  // Argument must be final to use inside

  // anonymous inner class:

  public Destination dest(final String dest) {//这个dest必须设置为final

  return new Destination() {

  private String label = dest;

  public String readLabel() { return label; }

  };

  }

  public static void main(String[] args) {

  Parcel8 p = new Parcel8();

  Destination d = p.dest("Tanzania");

  }

  }

  复制代码

  17、实际上,内部类的一个实例初始化模块就是一个匿名内部类的构造器。初次之外,内部类拥有对封装类所有元素的访问权限。

  18、设计构造器时一个特别有效的规则是:用尽可能简单的方法使对象进入就绪状态;如果可能,避免调用任何方法。在构造器内唯一能够安全调用的是在基础类中具有final 属性的那些方法(也适用于 private方法,它们自动具有 final 属性)

  19、泛型类或者泛型方法中,不接受 8 种基本数据类型。

  三、集合

  1、为容纳一组对象,最适宜的选择应当是数组,但是数组也有他明显的缺点,即容量有限。而且假如容纳的是一系列基本数据类型,更是必须采用数组。集合实际容纳的类型为Object的引用,这当然包括一切的java对象,因为Object是一切对象的基类。当然并不包括基本数据类型,因为它们并不是从“任何东西”继承来的。

  2、Iterator接口的remove方法将会删除上次调用next方法时返回的元素。集合也有一个remove的方法,适用于List 和 Set ,boolean remove(Object)。

  3、Listiterator和Iterator 的区别?

  一.相同点

  都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用。

  二.不同点

  1.使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。

  2.ListIterator有add方法,可以向List中添加对象,而Iterator不能。

  3.ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。

  4.ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

  5.都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。

  4、Set集合都不能保存重复的数据,即使是TreeSet也只是对不重复的数据进行排序罢了。对于TreeSet或者HashSet来说,在进行add()以及contain()操作时,HashSet显然要比ArraySet出色的多,而且性能明显与元素的多寡关系不大。一般在元素比较少,而且要进来遍历查询的时候,TreeSet会稍微快一些。

  5、HashSet 与TreeSet和LinkedHashSet的区别?

  HaseSet:

  1、不能保证元素的排列顺序,顺序有可能发生变化。

  2、不是同步的。

  3、集合元素可以为null,但只能放入一个null。

  4、当向HashSet集合中存入一个元素时,会首先调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。如果该HashSet集合中已经有这个对象的hashCode值,则调用该对象的equal()方法,返回true,就不插入,返回false,就另外找一个hashCode存储。

  TreeSet:

  TreeSet底层是一个红黑二叉树结构,其中元是不可重复的。TreeSet类型是J2SE中唯一可实现自动排序的类型。TreeSet支持两种排序方式,自然排序和定制排序。向treeSet中加入的应该是同一个类的对象。向TreeSet插入基本数据类型时,Java已经定义好了CompareTo(Object obj)方法,采用自然排序,默认升序。如果放入的是自定义的对象类需要实现Comparable接口并重写compareTo()方法,相等返回0,大于返回正数,小于返回负数。同时treeSet的插入比较也是通过compareTo()或者equal()方法来比较插入的。

  LinkedHashSet:

  LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺 序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。

  LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet

  6、如果两个对象相同,那么他们的hashCode值一定相同。如果两个对象的hashCode值相同,他们不一定相同。

  7、HashMap、TreeMap 的区别?

  1、HashMap是基于散列表实现的,时间复杂度能达到O(1),是无序的。

  2、TreeMap基于红黑树(一种自平衡二叉查找书)实现的,时间复杂度平均能达到O(log n),是有序的。

  8、HashMap、HashTable的区别?

  1、HashMap几乎可以等价于HashTable,都实现了Map接口。

  2、HashMap是非同步的,线程不安全的。而HashTable是同步的,线程安全的。当然我们也可以手动进行HashMap同步(Collections.synchronizeMap(hashMap))

  3、HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

  4、哈希值的使用不同,HashTable直接使用对象的hashCode。

  9、从性能方面来说,对于Map的put()和get(),hashMap和hashTable都要优于TreeMap,而hashTable要多花一些开销在线程同步上,所以hashMap的性能又稍优于hashTable。而对于Map的遍历来说,treeSet的性能要稍优于hashMap和hashTable。

  10、如果需要创建大量Map,TreeMap、hashMap的性能要优于hashTable。

  11、对于Arrays和Collections来说,若在执行一次 binarySearch()之前不调用 sort(),便会发生不可预测的行为,其中甚至包括无限循环。排序遵守的是字典排序,亦即大写字母在字符集中位于小写字母的前面。

  12、Comparator和Comparable的区别?

  集合或者数组要实现自动排序功能,比如TreeSet、TreeMap、Arrays.sort()、Collections.sort(),有两种方式。

  第一种:比较的类型内部实现了Comparable接口重写了compareTo()方法。

  第二种:自己新建了一个比较类实现了Comparator接口,重写了compare方法。

  13、使 Collection 或 Map 不可修改?

  Collections.unmodifiableCollection(c);

  Collections.unmodifiableList(a);

  Collections.unmodifiableSet(s);

  Collections.unmodifiableMap(m);

  14、使Collection 或 Map 的同步?

  Collections.synchronizedCollection(new ArrayList());

  Collections.synchronizedList(new ArrayList());

  Collections.synchronizedSet(new HashSet());

  Collections.synchronizedMap(new HashMap());

  四、其他

  1、怎么理解TCP是可靠的协议,而HTTP基于IP/TCP协议,却是不可靠的?

  1、首先IP 是网络层的协议,确认source和target的IP地址。

  2、TCP是传输层的传输协议,传输基于三次握手过程提供可靠的传输协议。

  3、HTTP是应用层协议,它只负责把服务器的资源反馈到客户端。

  4、怎么理解三个协议之间的合作呢,IP提供源地址和目标地址,TCP建立可靠的通道,最后由HTTP来负责传输内容,如果一个会话需要多个层级的连接,会造成延迟大、资源浪费,所以如果一个层级已经提供了可靠连接,则其它层级完全没有必要连接,只需要交流信息即可,比如这里的HTTP。