Java学习常见的易错点、难点(一)

1、作用域public,private,protected, 以及不写时的区别
 答:区别如下:
 作用域     当前类      同一 package  子孙类       其他package
    public            √                                     
    protected                                              ×
    friendly                                  ×              ×
    private           √               ×        ×              × 
不写时默认为 friendly

2Anonymous Inner Class ( 匿名内部类) 是否可以 extends继承 )其它类,是否可以 implements(实现)interface( 接口)
答:匿名的内部类是没有名字的内部类。不能 extends(继承 ) 其它类,但一个内部类可以作
为一个接口,由另一个内部类实现

3.Collection Collections 的区别
答:Collection是集合类的上级接口,继承与他的接口主要有 Set  List.Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作

4.String s=new String("jzy");创建了几个对象

5.抽象类不一定包含抽象方法,覆盖方法抛出的异常不能比原方法多,子类中访问权限不能比原方法更严格。

6.不能在静态方法中使用this。

7.编译MyClass.java之后,得到了三个字节码文件:MyClass.class , MyClasslittle$.class MyClass$1.class.这表明什么
答: MyClass类中有两个内部类:一个是命名的little,另一个是匿名的1

8.当方法遇到异常又不知如何处理时,应该怎么做抛出异常

9.类的加载和构造方法的调用顺序  
类的加载的顺序:先递归地加载父类的静态成员/代码块(object的最先);再依次加载
到本类的静态成员。  调用构造方法:先递归地调用父类的构造方法;默认调用父类空参的同,也可在第一行写明调用用父类某个带参的。再依次到本类的构造方法;  先初始化父类的静态代码--->初始化子类的静态代码-->                 == ==(创建实例时,如果不创建实例,则后面的不执行)初始化父类的非静态代码---> == ==初始化父类构造函数--->初始化子类非静态代码--->初始化子类构造函数    ==

10.在异常处理中若try中的代码可能产生多种异常则可以对应多个catch语句,若catch中的参数类型有父类子类关系,此时应该将父类放在后面,子类放在前面。

11.while循环判断条件一般是程序结果,for循环的判断条件一般是非程序结果

12.一个接口实现多个接口用extends
如:
public interface 新接口 extends 交通工具, 金属制品 {

}

13.数组旋转90°座标变换
假设该数组为 a[n][n], 
其中的一个元素为  a[x][y],
顺时针旋转 90度后, 该元素的座标为  a[y][n-x]
14.所有类的对象其实都是Class的实例
15.Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据的访问。另外,你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件中出现。
16.方法和属性的继承(方法属性子类和父类都声明了)
        Parent a=new Child();
        a.showData();      //调用的是子类的方法
        System. out.println(a. i);      //调用的是父类的属性
17.实例变量:定义在类中但在任何方法之外。(New出来的均有初值)
局部变量:定义在方法之中的变量。
局部变量要先赋值,再进行运算,而实例变量均已经赋初值。这是局部变量和实例变量的一大区别。
18.构造方法
注意:构造方法在生成对象的时候会被调用,但并不是构造方法生成了对象。
构造方法是在对象生成的过程中自动调用,不可能利用指令去调用。
在一个对象的生成周期中构造方法只用一次,一旦这个对象生成,那么这个构造方法失效。
可以构造多个构造方法,但多个构造方法的参数表一定不同,参数顺序不同即属于不同的构造方法:
public student(string name,int a){
}
public student(int a,string name){
}
为两个不同的构造方法。
在构造方法中, this表示本类的其他构造方法:
student(){};
student(string n){
  this();// 表示调用student()
}
如果调用 student(int a)则为this(int a)
特别注意 this调用其他构造方法时,this必须为第一条语句,然后才是其他语句
19.this
This表示当前对象。

Public  void  printNum(){
  Int number=40 
  System.out.println(this.number);
}
此时打印的是实例变量,而非局部变量,即定义在类中而非方法中的变量。
This.number表示实例变量。
谁调用 this.number那么谁即为当前(this)对象的number 方法。
如果不指明谁调用方法,则默认为 this 。
区分实例变量和局部变量时一定要写 this 。
20.封装:使对象的属性尽可能私有,对象的方法尽可能的公开。用 private表示此成员属性为该类的私有属性。
Public表示该属性(方法)公开;
Private表示该属性(方法)为只有本类内部可以访问(类内部可见)。
(想用 private还要用setget方法供其他方法调用,这样可以保证对属性的访问方式统一,并且便于维护访问权限以及属性数据合法性)
如果没有特殊情况,属性一定私有,方法该公开的公开。
21.继承

而如果父类中的私有方法被子类调用的话,则编译报错。

父类的构造方法子类不可以继承,更不存在覆盖的问题。(非构造方法可以)

如果子类访问父类的构造方法,则在编译的时候提示访问不到该方法。

对于方法的修饰词,子类方法要比父类的方法范围更加的宽泛。

父类为 public,那么子类为private则出现错误。

之所以构造方法先运行父类再运行子类是因为构造方法是无法覆盖的。
当构造一个对象的时候,系统先构造父类对象,再构造子类对象。
构造一个对象的顺序:(注意:构造父类对象的时候也是这几步)
①     递归地构造父类对象;
②     顺序地调用本类成员属性赋初值语句;
③     本类的构造方法。

Super()表示调用父类的构造方法。
Super()也和this一样必须放在第一行。
This()用于调用本类的构造方法。
如果没有定义构造方法,那么就会调用父类的无参构造方法,即super()。

要养成良好的编程习惯:就是要加上默认的父类无参的构造方法。
思考:可是如果我们没有定义无参的构造方法,而在程序中构造了有参的构造方法,那么如果方法中没有参数,那么系统还会调用有参的构造方法么?应该不会。
22.多态
多态:多态指的是编译时类型变化,而运行时类型不变。
多态分两种:
①     编译时多态:编译时动态重载;
②     运行时多态:指一个对象可以具有多个类型。

对象是客观的,人对对象的认识是主观的。
例:
Animal a=new Dog();查看格式名称;
Dog d=(Dog)a。声明父类来引用子类。
(思考上面的格式)

运行时多态的三原则:(应用时为覆盖)
1、     对象不变;(改变的是主观认识)
2、     对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。
在上面的例子中:Animal a=new Dog();对象a的编译时类型为Animal,运行时类型为dog。
注意:编译时类型一定要为运行时类型的父类(或者同类型)。
对于语句:Dog d=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就可以调用运行时类型。注意:a和d指向同一对象。

23.关系运算符: instanceof

a  instanceof Animal;(这个式子的结果是一个布尔表达式 )

a为对象变量, Animal是类名。

上面语句是判定a是否可以贴 Animal标签。如果可以贴则返回 true,否则返回false 

在上面的题目中: a instanceof Animal返回 True 

                 a instanceof Dog 也返回 True

instanceof用于判定是否将前面的对象变量赋值后边的类名。

Instanceof一般用于在强制类型转换之前判定变量是否可以强制转换。
24.static

静态方法中不允许访问类的非静态成员,包括成员的变量和方法,因为此时是通过类调用的,没有对象的概念。 This.data是不可用的。

一般情况下,主方法是静态方法,所以可调用静态方法,主方法为静态方法是因为它是整个软件系统的入口,而进入入口时系统中没有任何对象,只能使用类调用。

覆盖不适用于静态方法。

静态方法不可被覆盖。(允许在子类中定义同名静态方法,但是没有多态,严格的讲,方法间没有多态就不能称为覆盖)

static修饰代码块时(注:此代码块要在此类的任何一个方法之外),那么这个代码块在代码被装载进虚拟机生成对象的时候可被装载一次,以后再也不执行了。

一般静态代码块被用来初始化静态成员。

Static通常用于Singleton 模式开发:

Singleton是一种设计模式,高于语法,可以保证一个类在整个系统中仅有一个对象。
25.final

final可以修饰类、属性、方法。

当用final修饰类的时候,此类不可被继承,即final类没有子类。这样可以用final保证用户调用时动作的一致性,可以防止子类覆盖情况的发生。

当利用final修饰一个属性(变量)的时候,此时的属性成为常量。

JAVA利用final定义常量(注意在JAVA命名规范中常量需要全部字母都大写):

Final int AGE=10

常量的地址不可改变,但在地址中保存的值(即对象的属性)是可以改变的。

Final可以配合static使用。  

Static final int age=10

JAVA中利用public static final的组合方式对常量进行标识(固定格式)。

对于在构造方法中利用final进行赋值的时候,此时在构造之前系统设置的默认值相对于构造方法失效。

常量(这里的常量指的是实例常量:即成员变量)赋值:

①在初始化的时候通过显式声明赋值。Final int x=3

②在构造的时候赋值。

局部变量可以随时赋值。

利用final定义方法:这样的方法为一个不可覆盖的方法。

Public final void print(){}

为了保证方法的一致性(即不被改变),可将方法用final定义。

如果在父类中有final定义的方法,那么在子类中继承同一个方法。

如果一个方法前有修饰词privatestatic,则系统会自动在前面加上final。即privatestatic方法默认均为final方法。

注:final并不涉及继承,继承取决于类的修饰符是否为privatedefaultprotected还是public。也就是说,是否继承取决于这个方法对于子类是否可见。
final修饰基本数据类型表示该属性不能被改写,修饰引用数据类型表示该应用不能再指向其他对象,但对象的内容可以发生变化。
26.abstract

Abstract(抽象)可以修饰类、方法

Abstract虽然不能生成对象,但是可以声明,作为编译时类型,但不能作为运行时类型。

Finalabstract永远不会同时出现。

注意比较:

private void print(){};此语句表示方法的空实现。

Abstract void print(); 此语句表示方法的抽象,无实现。

如果一个类中有一个抽象方法,那么这个类一定为一个抽象类。

反之,如果一个类为抽象类,那么其中可能有非抽象的方法。

如果让一个非抽象类继承一个含抽象方法的抽象类,则编译时会发生错误。因为当一个非抽象类继承一个抽象方法的时候,本着只有一个类中有一个抽象方法,那么这个类必须为抽象类的原则。这个类必须为抽象类,这与此类为非抽象冲突,所以报错。

所以子类的方法必须覆盖父类的抽象方法。方法才能够起作用。

Abstractstatic不能放在一起,否则便会出现错误。(这是因为static不可被覆盖,而abstract为了生效必须被覆盖。
27.interface
JAVA的核心概念:接口(interface)
与类相似,一个文件只能有一个public接口,且与文件名相同。
在一个文件中不可同时定义一个public接口和一个public类。
一个接口中,所有方法为公开、抽象方法;所有的属性都是公开、静态、常量。
类必须实现接口中的方法,否则其为一抽象类。
实现中接口和类相同。
接口中可不写public,但在子类中实现接口的过程中public不可省。
(如果剩去public则在编译的时候提示出错:对象无法从接口中实现方法。)

①     接口和接口之间可以定义继承关系,并且接口之间允许实现多继承。
例:interface IC extends IA,IB{};

接口实际上是定义一个规范、标准。

①     通过接口可以实现不同层次、不同体系对象的共同属性;
通过接口实现write once as anywhere.
以JAVA数据库连接为例子:JDBC制定标准;数据厂商实现标准;用户使用标准。
接口通常用来屏蔽底层的差异。
②接口也因为上述原因被用来保持架构的稳定性。

JAVA中有一个特殊的类: Object。它是JAVA体系中所有类的父类(直接父类或者间接父类)。

此类中的方法可以使所的类均继承。
以下介绍的三种方法属于Object:
(1)     finalize方法:当一个对象被垃圾回收的时候调用的方法。
(2)     toString():是利用字符串来表示对象。
当我们直接打印定义的对象的时候,隐含的是打印toString()的返回值。
可以通过子类作为一个toString()来覆盖父类的toString()。
以取得我们想得到的表现形式,即当我们想利用一个自定义的方式描述对象的时候,我们应该覆盖toString()。
28.String

字符串类为 JAVA中的特殊类,String中为 final类,一个字符串的值不可重复。因此在 JAVA VM(虚拟机)中有一个字符串池,专门用来存储字符串。如果遇到 String a=”hello”时(注意没有 NEW,不是创建新串),系统在字符串池中寻找是否有 ”hello”,此时字符串池中没有”hello”,那么系统将此字符串存到字符串池中,然后将 ”hello”在字符串池中的地址返回 a。如果系统再遇到String b=”hello”,此时系统可以在字符串池中找到  “hello”。则会把地址返回b,此时 ab 为相同。

String a=”hello”;

System.out.println(a==”hello”);

系统的返回值为 true

故如果要比较两个字符串是否相同(而不是他们的地址是否相同)。可以对 a调用equal:

System.out.println(a.equal(b));

equal用来比较两个对象中字符串的顺序。

a.equal(b) ab 的值的比较。


注意下面程序:

student a=new student(“LUCY”,20);

student b=new student(“LUCY”,20);

System.out.println(a==b);

System.out.println(a.equal(b));

此时返回的结果均为false

以下为定义 equal(加上这个定义,返回ture false

public boolean equals(Object o){

  student s=(student)o;

  if (s.name.equals(this.name)&&s.age==this.age)

else return false;

}如果equals() 返回的值为


以下为实现标准 equals的流程:

public boolean equals(Object o){

  if (this==o) return trun;  // 此时两者相同
  if (o==null) return false;

  if (! o instanceof strudent) return false;  // 不同类

  studeng s=(student)o; // 强制转换

  if (s.name.equals(this.name)&&s.age==this.age) return true;

else return false;

}

==”在任何时候都是比较地址,这种比较永远不会被覆盖。


以上过程为实现 equals的标准过程。
29.Java序列化

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,即Java对象序列号,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象,即反序列化。

把Java对象转换为字节序列的过程称为对象的序列化

把字节序列恢复为Java对象的过程称为对象的反序列化

对象的序列化主要有两种用途:

1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

2) 在网络上传送对象的字节序列。
30.内部类
封装类:
JAVA为每一个简单数据类型提供了一个封装类,使每个简单数据类型可以被Object来装载。
除了int和char,其余类型首字母大写即成封装类。
转换字符的方式:
int I=10;
String s=I+” ”;
String s1=String.valueOf(i);

Int I=10;
Interger I_class=new integer(I);


看javadoc的帮助文档。
附加内容:
“==”在任何时候都是比较地址,这种比较永远不会被覆盖。

程序员自己编写的类和JDK类是一种合作关系。(因为多态的存在,可能存在我们调用JDK类的情况,也可能存在JDK自动调用我们的类的情况。)
注意:类型转换中double\interger\string之间的转换最多。
12.01
内部类:
(注:所有使用内部类的地方都可以不用内部类,使用内部类可以使程序更加的简洁,便于命名规范和划分层次结构)。
内部类是指在一个外部类的内部再定义一个类。
内部类作为外部类的一个成员,并且依附于外部类而存在的。
内部类可为静态,可用PROTECTED和PRIVATE修饰。(而外部类不可以:外部类只能使用PUBLIC和DEFAULT)。

内部类的分类:
成员内部类、
局部内部类、
静态内部类、
匿名内部类(图形是要用到,必须掌握)。

①     成员内部类:作为外部类的一个成员存在,与外部类的属性、方法并列。
内部类和外部类的实例变量可以共存。
在内部类中访问实例变量:this.属性
在内部类访问外部类的实例变量:外部类名.this.属性。

成员内部类的优点:
⑴内部类作为外部类的成员,可以访问外部类的私有成员或属性。(即使将外部类声明为PRIVATE,但是对于处于其内部的内部类还是可见的。)
⑵用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。
对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。

(编写一个程序检验:在一个TestOuter.java程序中验证内部类在编译完成之后,会出现几个class.)

成员内部类不可以有静态属性。(为什么?)

如果在外部类的外部访问内部类,使用out.inner.

建立内部类对象时应注意:
在外部类的内部可以直接使用inner s=new inner();(因为外部类知道inner是哪个类,所以可以生成对象。)
而在外部类的外部,要生成(new)一个内部类对象,需要首先建立一个外部类对象(外部类可用),然后在生成一个内部类对象。
Outer.Inner in=Outer.new.Inner()。
错误的定义方式:
Outer.Inner in=new Outer.Inner()。
注意:当Outer是一个private类时,外部类对于其外部访问是私有的,所以就无法建立外部类对象,进而也无法建立内部类对象。

②     局部内部类:在方法中定义的内部类称为局部内部类。
与局部变量类似,在局部内部类前不加修饰符public和private,其范围为定义它的代码块。

注意:局部内部类不仅可以访问外部类实例变量,还可以访问外部类的局部变量(但此时要求外部类的局部变量必须为final)??
在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。
要想使用局部内部类时需要生成对象,对象调用方法,在方法中才能调用其局部内部类。

③     静态内部类:(注意:前三种内部类与变量类似,所以可以对照参考变量)
静态内部类定义在类中,任何方法外,用static定义。
静态内部类只能访问外部类的静态成员。
生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。静态内部类的对象可以直接生成:
Outer.Inner in=new Outer.Inner();
而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。
静态内部类不可用private来进行定义。例子:
对于两个类,拥有相同的方法:
People
{
  run();
}
Machine{
   run();
}
此时有一个robot类:
class Robot extends People implement Machine.
此时run()不可直接实现。
注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。
用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。

④     匿名内部类(必须掌握):
匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。
IA被定义为接口。
IA I=new IA(){};
注:一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。
因其为局部内部类,那么局部内部类的所有限制都对其生效。
匿名内部类是唯一一种无构造方法类。
匿名内部类在编译的时候由系统自动起名Out$1.class。

如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。
因匿名内部类无构造方法,所以其使用范围非常的有限。
31Exception
Exception有两个子类:Runtime exception(未检查异常)
非Runtime exception(已检查异常)
(注意:无论是未检查异常还是已检查异常在编译的时候都不会被发现,在编译的过程中检查的是程序的语法错误,而异常是一个运行时程序出错的概念。)
在Exception中,所有的非未检查异常都是已检查异常,没有另外的异常!!

未检查异常是因为程序员没有进行必要的检查,因为他的疏忽和错误而引起的异常。一定是属于虚拟机内部的异常(比如空指针)。

应对未检查异常就是养成良好的检查习惯。
已检查异常是不可避免的,对于已检查异常必须实现定义好应对的方法。
已检查异常肯定跨越出了虚拟机的范围。(比如“未找到文件”)

如何处理已检查异常(对于所有的已检查异常都要进行处理):
首先了解异常形成的机制:
当一个方法中有一条语句出现了异常,它就会throw(抛出)一个例外对象,然后后面的语句不会执行返回上一级方法,其上一级方法接受到了例外对象之后,有可能对这个异常进行处理,也可能将这个异常转到它的上一级。
对于接收到的已检查异常有两种处理方式:throws和try方法。

注意:出错的方法有可能是JDK,也可能是程序员写的程序,无论谁写的,抛出一定用throw。

例:public void print() throws Exception.

对于方法a,如果它定义了throws Exception。那么当它调用的方法b返回异常对象时,方法a并不处理,而将这个异常对象向上一级返回,如果所有的方法均不进行处理,返回到主方法,程序中止。(要避免所有的方法都返回的使用方法,因为这样出现一个很小的异常就会令程序中止)。

如果在方法的程序中有一行throw new Exception(),返回错误,那么其后的程序不执行。因为错误返回后,后面的程序肯定没有机会执行,那么JAVA认为以后的程序没有存在的必要。
Try中如果发现错误,即跳出try去匹配catch,那么try后面的语句就不会被执行。
一个try可以跟进多个catch语句,用于处理不同情况。当一个try只能匹配一个catch。
我们可以写多个catch语句,但是不能将父类型的exception的位置写在子类型的excepiton之前,因为这样父类型肯定先于子类型被匹配,所有子类型就成为废话。JAVA编译出错。

在try,catch后还可以再跟一子句finally。其中的代码语句无论如何都会被执行(因为finally子句的这个特性,所以一般将释放资源,关闭连接的语句写在里面)。

如果在程序中书写了检查(抛出)exception但是没有对这个可能出现的检查结果进行处理,那么程序就会报错。

Exception有一个message属性。在使用catch的时候可以调用:
Catch(IOException e){System.out.println(e.message())};
Catch(IOException e){e.printStackTrace()};
上面这条语句回告诉我们出错类型所历经的过程,在调试的中非常有用。

开发中的两个道理:
①如何控制try的范围:根据操作的连动性和相关性,如果前面的程序代码块抛出的错误影响了后面程序代码的运行,那么这个我们就说这两个程序代码存在关联,应该放在同一个try中。
①     对已经查出来的例外,有throw(积极)和try catch(消极)两种处理方法。
对于try catch放在能够很好地处理例外的位置(即放在具备对例外进行处理的能力的位置)。如果没有处理能力就继续上抛。

当我们自己定义一个例外类的时候必须使其继承excepiton或者RuntimeException。
Throw是一个语句,用来做抛出例外的功能。
而throws是表示如果下级方法中如果有例外抛出,那么本方法不做处理,继续向上抛出。
Throws后跟的是例外类型。
32.断言

断言是一种调试工具(assert

其后跟的是布尔类型的表达式,如果表达式结果为真不影响程序运行。如果为假系统出现低级错误,在屏幕上出现assert信息。

Assert只是用于调试。在产品编译完成后上线assert代码就被删除了。

 

方法的覆盖中,如果子类的方法抛出的例外是父类方法抛出的例外的父类型,那么编译就会出错:子类无法覆盖父类。

结论:子类方法不可比父类方法抛出更多的例外。子类抛出的例外或者与父类抛出的例外一致,或者是父类抛出例外的子类型。或者子类型不抛出例外。

如果父类型无throws时,子类型也不允许出现throws。此时只能使用try catch

33.HashMap 
底层也是用数组,HashSet底层实际上也是 HashMapHashSet 类中有HashMap属性(我们如何在 API中查属性)。HashSet实际上为 (key.null)类型的HashMap 。有key值而没有 value值。

正因为以上的原因, TreeSetTreeMap 的实现也有些类似的关系。


注意: TreeSetTreeMap 非常的消耗时间,因此很少使用。

HashSet VS TreeSetHashSet 非常的消耗空间, TreeSet因为有排序功能,因此资源消耗非常的高,我们应该尽量少使用,而且最好不要重复使用。

基于以上原因,我们尽可能的运用 HashSet而不用TreeSet ,除非必须排序。

同理: HashMap  VS  TreeMap:一般使用HashMap ,排序的时候使用 TreeMap


HashMap VS Hashtable(注意在这里table的第一个字母小写)之间的区别有些类似于 ArrayListVector Hashtable是重量级的组件,在考虑并发的情况,对安全性要求比较高的时候使用。
34.hashcode

一致性

在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。

equals

如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果,注:这里说的equals(Object) 方法是指Object类中未被子类重写过的equals方法。
如果两个hashCode()返回的结果相等,则两个对象的equals方法不一定相等。

附加

如果根据equals(java.lang.Object)方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

编辑本段重写HashMap对象是根据其Key的hashCode来获取对应的Value。

在重写父类的equals方法时,也重写hashcode方法,使相等的两个对象获取的HashCode也相等,这样当此对象做Map类中的Key时,两个equals为true的对象其获取的value都是同一个,比较符合实际。
1:Object类的hashCode.返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
2:String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串内容相同,返回的哈希码也相同。
3:Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。


35.io流
 在流中close()方法由程序员控制。因为输入输出流已经超越了VM的边界,所以有时可能无法回收资源。原则:凡是跨出虚拟机边界的资源都要求程序员自己关闭,不要指望垃圾回收。以Stream结尾的类都是字节流。(非重点)管道流:也是一种节点流,用于给两个线程交换数据。

PipedOutputStream

PipedInputStream

输出流:connect(输入流) 

RondomAccessFile类允许随机访问文件GetFilepoint()可以知道文件中的指针位置,使用seek()定位。Mode(“r”:随机读;”w”:随机写;”rw”:随机读写)Io包的InputStreamread称为从字节流到字符流的桥转换类。这个类可以设定字符转换方式。

OutputStreamred:字符到字节

Bufferreadreadline() 使得字符输入更加方便。

I/O流中,所有输入方法都是阻塞方法。

Bufferwrite给输出字符加缓冲,因为它的方法很少,所以使用父类 printwrite,它可以使用字节流对象,而且方法很多。用流传输对象称为对象的序列化,但并不使所有的对象都可以进行序列化的。只有在实现类时必须实现一个接口:IO包下的Serializable(可序列化的)。此接口没有任何的方法,这样的接口称为标记接口。

Class Student implements Serializable

把对象通过流序列化到某一个持久性介质称为对象的可持久化。Transient用来修饰属性。

 Transient int num;

表示当我们对属性序列化时忽略这个属性(即忽略不使之持久化)。

所有属性必须都是可序列化的,特别是当有些属性本身也是对象的时候,要尤其注意这一点。判断是否一个属性或对象可序列化: SerialverSerialver TestObjectTestObject 必须为已经编译)
36.toString()

toString方法是一个“自我描述"的方法,要输出自我有用的信息,要重写该方法。
37.SuppressWarnings
取消编译时的警告
38.线程
一般用Runnable接口,不用Thread类,Runnable可以实现数据共享

39.静态方法只能继承,不能重写
接口成员变量必须赋初值

40.float类型
共32位(不int相同),其中1位为符号位, 指数8位, 尾数23位。需要强调的是float的精度是23位(即能精确表达23位的数,超过就被截叏了)。小数是以尾数长度来表示精确度的,比如pi=3.14,它的精度是2位,pi=3.1415,它的精度就为4位。 比较有趣的是int的精度比float要大,因为int的精度是31位,大于float。因为int类型的范围是(-2^31)~(2^31-1),而float的范围是(-2^128)~(-2^128-1),所以记住: int类型的数据能表示的范围比float类型小,int类型数据表示的精度比float大。 double类型能表示64位,其中1位符号位,11位指数,52位尾数.double精度比int精确,但是丌如long;double范围进进大于long。 需要注意的是,浮点数的字面量 默认是double, D d 后缀是double, f F 是float。如下 图-20所示会出现编译错诨,原理同int和long
字符类型是一个16位无符号整数, 是一个2迚制数,这个数值是一个字符的 unicode编码值。

41. 取模的规律:取模的结果符号永远与被除数的符号相同
int a = 5;
int b = -3;
int c = a % b;
被除数是5,那么取模的结果是 2
int a = -5;
int b = 3;
int c = a % b;
被除数是-5,那么取模的结果是-2

42.栈,
Java中所有的局部变量都是在栈内存中分配的(包括方法中声明的变量、方法的参数) 。 
Java方法调用使用栈实现, 递归调用就是栈实现的。递归时候要按照递归深度分配全部临时变量 , 栈开销很大, 性能不好, 要注意不要超过栈的大小 , 幵且一定要给出结束条件 , 否则会造成栈溢出错诨。
栈存储方式会有风险,以这种"对柴火"的方式存储数据会造成 栈溢出windows平台下,JVM默认的栈空间为64M字节,也可以通过优化参数修改,此处不做详解。 
栈内存空间的存储特点是后迕先出”,堆内存空间的存储特点和栈丌同,类似于一盘散沙,随处可以“堆放”



局部变量与堆对象空间分配

ü Java 局部变量和方法参数在栈中分配,大小是按照变量的类型分配

ü 对象在堆中分配,按照类中声明属性( 实例变量)分配空间 

ü 基本类型变量的空间大小:就是基本类型的空间大小,值是基本类型的值

ü 引用变量的值是一个对象的地址值,引用变量通过地址引用了一个堆对象

ü 引用类型变量的占用空间大小和值管理是“透明的(丌可看见)”由Java系统管理:变量占用空间以及值的管理,都是透明的 
this是局部变量,构造方法调用结束后和参数一样消失 

43.java方法参数的传递规则:基于值的传递

ü Java方法参数传递只有一种方式,基于值的传递,是变量值的复制

ü 基本类型就是其中值的复制

ü 引用类型是引用值(地址)的复制 

44.静态导入:(静态方法调用时可省略掉静态方法的类名)
import static +路径名+类名+方法名或成员变量名;

 
45.局部变量使用前必须要声明并赋初值;成员变量使用前必须要声明,但可以不赋初值。 
 
引用类型是用在对象上的。一个对象可以被多个引用所指向,但同一时刻,每个引用只能指向唯一的一个对象。如果一个对象被多个引用所指向,那么无论哪个引用对对象的属性进行了修改,都会反映到其他的引用当中。 

46  new关键字在生成对象时完成了三件事情:

a) 为对象开辟内存空间。

b) 调用类的构造方法。

c) 将生成的对象的地址返回。 
e) 不能显式调用类的构造方法,构造方法通常是通过 new关键字隐式调用。 

47.构造器

ü 构造器丌能继承!

ü 实例化子类,会递归分配所有父类的空间

ü 子类构造器一定调用父类构造器

ü 类一定有构造器(父类、子类) 

48.多态:父类型引用子类型,编译期丌确定什么类型(统一都是Question的),运行期才能确定

ü q和check()方法都是通过”对象的劢态绑定“ 实现的多态现象 

Java引用变量有两种类型:一个 编译期类型,一个 运行时类型。编译时类型由该声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定,如果编译时类型和运行时类型丌一致,就会出现“多态”现象 

使用super()调用父类构造器,必须写在子类构造器第一行

ü this() 必须写在子类构造器第一行

ü 有super()就丌能有this(),两者互斥 
this编译时不存在,运行时才出现 

如果父类没有无参数构造器,就必须在子类中明确指定调用父类的有参数构造器!

ü 编程建议:所有的类都提供无参数构造器!减少继承时候的麻烦 

理解Java中对象实例化过程是很重要的 ,实例化过程主要步骤如下: 第1步: 在创建类乊前,检查类是否 加载(是将硬盘上的.class文件加载到内存中),如果没有加 载就加载这个类,在这个类加载乊前要加载所有父类。 Java运行时采用的策略:懒惰式加载(按需加载):如果第一次用到就加载,只加载一 次。通过CLASSPATH指定的路径寻找类文件(.class),加载以后是一个对象,类型是 Class。 第2步: 在内存堆中分配对象空间。递归分配所有父类和子类属性空间。 达内 IT 培训集团 33

属性默认自劢初始化。自劢初始化为“0”值。 第3步: 迚行属性的赋值。 第4步: 递归调用父类构造器。(默认调用父类无参数构造器!) 第5步: 调用本类构造器。 


49.方法的覆盖是由方法动态绑定实现的
是Java虚拟机运行时候确定执行哪个对象哪个方法,java最终执行子类的方法 
在实际项目开发中,原则上丌允许使用final类!
Spring, Hibernate,Struts 2, 这些框架使用了"动态继承代理"技术,使用final的类会影响"动态代理技术" 的实现. 
final修饰属性表示“丌能改”,static修饰属性表示属于类的“仅此一份”,注意区分
 知识点:
 final的局部变量,只能初始化丌能改
 final的方法参数,丌能改
 final的引用,引用指向丌能改,但是对象的属性可以改

比较引用值是否相等: “ ==

u 比较对象的内容是否相等: xxx.equals()方法 
默认的hashCode()值是当前堆对象地址转换的一个整数,这个整数 不是内存地址 ! 
50. 关于继承的注意事项

a) 构造方法不能被继承

b) 方法和属性可以被继承

c) 子类的构造方法隐式地调用父类的不带参数的构造方法

d) 当父类没有不带参数的构造方法时,子类需要使用 super来显


式地调用父类的构造方法, super指的是对父类的引用

e) super关键字必须是构造方法中的第一行语句。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章