java面试知识点汇总1

来源:互联网 发布:产品网络推广方案 编辑:程序博客网 时间:2024/06/04 19:52

类结构:变量和方法

被static修饰的:是类的属性与方法  -----静态变量和静态方法
非static修饰的:是对象的属性与方法 ----成员变量和成员方法
静态方法或者成员方法内声明的变量 ---局部变量(必须初始化)

区别:1.类属性和方法被所有的对象共享,如果一个对象改变他的
        值,那么其他对象访问的都是改变后的值。
      2.成员变量和方法不能通过类名直接调用,
        必须创建对象后方可调用,他被指定的对象所特有,
        如果一个对象改变他的值
        那么其他对象访问的值不受影响。 

静态和成员之间的调用关系:
1.静态函数不能调用成员变量或成员函数(因为在类加载时非静态方法区只是母版区,不可用,
                                   就算可用,在堆内生成了多个对象,他也不知道调的是哪一个)
2.成员函数可以调用静态变量或静态函数(因为在类加载时静态方法区是实实在在存在的,可用的)

----静态代码块:static{ 。。。。 }
静态代码块的作用:类一旦被加载就会调用,常用来测试代码,
使用案例如下:
class A{
  static{
     System.out.println("类A被加载了。。。");
  }
}

静态和非静态内存分配:
知识补充:类的主要4个组成部分:静态方法和函数,非静态的方法和函数
1.程序跑起来会产生一块运行时数据区,
  里面包含:栈,堆,方法区
2.接着将Dorm类加载进内存,而Dorm类中既有静态变量和方法,也有成员变量和方法,
  Dorm类被加载时(未创建对象),就会在方法区里面开辟一段内存用来存放dorm对象,
  该内存被分为两部分,一部分用来存放静态的变量和方法,另一部分则用来
  存放非静态的变量和方法,
-------两块内存的区别:
  类一旦被加载,静态方法区是实实在在存在的,可用的,而非静态区则只是作为母版区,
是不可用的,即非实在的,那该区什么时候可用呢?答案是:当类创建对象的时候。
3.当类创建对象时,会在堆里面产生一块内存存放该对象,并且该对象的内容就是母版区内容的复制,
  同理当创建了对个对象时,在堆里就会分配多个内存,并且都是母版区的复制,
4.存在于栈内的main对象中包含多个对象的声明,每一个分别指向对应的堆内的内存,
  但是却指向同一个静态方法区,即共享静态方法区,所以修改静态成员的值会影响
  其他对象访问,但修改成员变量或方法,只是改变了某个对象堆内的数据,因为指向不同,
  所以其他对象不受影响。



-----类加载进内存的时机:
     1.运行这个类的main主方法时
     2.其他的类调用这个类的静态变量或者静态函数时
     3.创建对象时
     4.使用反射 -- 如JDBC中的Class.forName()的使用

-----类加载时的内容以及顺序:
     1.类加载只加载静态的
     2.静态变量,静态函数,静态代码块static{}
类加载时会按照声明顺序,加载静态变量和静态代码块
而静态函数只是被加载进静态方法区,只有被调用时才会运行

构造函数:
1.构造函数是用来创建对象的,
  一般创建对象默认调用的是该类的无参的构造函数
2.构造函数还可以用来在创建对象时对对象进行初始化
3.构造函数没有static修饰,但却是静态的
4.当创建一个类时,如果没有定义构造函数,那么系统会默认
  提供一个无参的构造函数
5.当创建类的时候自己创建了一个有参的构造函数,默认的无参的
  构造函数就变得不可用,除非同时定义一个有参的和无参的构造函数

-----堆内的对象的加载时机:
     构造函数被调用时
对象在堆内被创建时对象要加载的内容:
1.构造代码块 --- 就是一个块语句,使用大括号括起来就行
2.成员变量
3.成员函数

如下类:
class A{
   public A(){
      System.out.println("对象被创建。。");
   }
   public String str = "成员变量";
   {
   System.out.println("构造代码块。。。");
   }
   public void test(){
     System.out.println("成员函数。。。");
   }
}

A a = new A();
创建对象执行的流程:
1.加载类
2.调用构造函数产生栈帧
3.在堆中创建对象
  在堆中创建对象要加载哪些内容:
  ---按照声明顺序加载成员变量和成员代码块
4.执行构造函数的方法体
5.将创建好的对象赋值给引用

------类与对象的加载:
面试题如下:

public class A{
  public static void main(String[] args){
    Load load1 = new Load();
    Load load2 = new Load();
  }
}
class Load{
    //静态代码块:类一旦加载就会被调用
    static{
    System.out.println("Load类被加载了。。。");    
    }
    //构造代码块:只有在创建对象的时候才会被调用
    {
    System.out.println("对象被加载了。。。");
    }
}

根据以上笔记对类和对象加载时机的说明以上程序的运行结果为:
Load类被加载了。。。
对象被加载了。。。
对象被加载了。。。

结果总结:
1.类只会被加载一次,即加载进方法区并分为静态和非静态,
  静态内容只在方法区加载一次,而非静态的则在每次堆内创建对象时对会被加载一次
2.对象每被创建一次就加载一次,对象的每一次加载都是对非静态方法区的复制,
  在堆内开辟新的空间

----完整地类与对象加载示例:
面试题:

public class A{
  public static void main(String[] args){
      B b = new B();
  }
}
class B{
  //静态方法区内容----------------------------------------------
  //静态变量
  public static String svar = C.getStaticVar();
  //静态方法
  public static void staticMethod(){
     System.out.println("静态方法。。。");
  }
  //静态代码块
  static{
     System.out.println("静态代码块。。。");
  }
  //构造方法
  public B(){
     System.out.println("构造方法。。。");
  }
  //---------------------------------------------------
  //母版区(非静态方法区)内容-----------------------------
  //1.构造代码块
  {
     System.out.println("构造代码块。。。");
   }
  //2.成员变量
   public String var = C.getVar();
  //3.成员函数
   public void method(){
      System.out.println("成员方法。。。");
   }
}
class C{
   public static String getStaticVar(){
     System.out.println("生成静态变量。。。");
     return "staticVar";
   }
   public static String getVar(){
     System.out.println("生成成员变量。。。");
     return "var";
   }
}



执行流程分析如下:
1.对象在被创建时先加载类,加载类时按照声明顺序加载静态代码块和静态变量,
而静态函数不运行,只有在调用时才运行。
2.静态区加载完毕然后开始创建对象,即加载对象进堆内,对象加载时
要加载构造代码块和成员变量和成员方法,成员方法同样也是
只被加载不被执行,在被调用时才执行。
3.等对象在堆内创建完毕,整个构造函数的执行过程就结束了,然后
再执行栈帧里面的构造函数方法体。

   3     ---  3   ---    1
类静态区 --- 对象 --- 构造方法

以上程序的运行结果为:
生成静态变量。。。
静态代码块。。。
构造代码块。。。
生成成员变量。。。
构造方法。。。



-------关键字final的使用---
我们知道类变量(即被static修饰的变量)被所有类对象共享,并且在其他类中可以通过
类名点的方式进行调用,这就存在问题:其他类在调用某个类的类变量时在调用之后修改了
他的值,这是我们所不愿看到的,那么如何避免类变量的值被修改呢?
答案是:使用关键字final修饰,并且规定:被final修饰的变量名称各个字母均要大写
class A{
 public final static int NUMBER = 4;
}

final修饰类:----- 此类不可以被继承,例如String类和所有的包装类(Integer等),还有数学类Math
  注意:Arrays类没有被final修饰,但是仍然不可以被继承,设置类不可被继承的其他方法
final修饰变量:---- 修饰静态变量时必须进行初始化,因为类一旦被加载静态字段就加载了,所以加在之前必须初始化
                   修饰成员变量时,因为成员变量只有在对象创建完成之后才可以使用,所以必须在对象
                   创建完成之前进行赋值
对象创建完成之前-----
A.构造代码块
B.构造函数体

final修饰方法:----不能被重写
函数修饰不可以同时出现final(不能重写)和abstract(要求重写),产生矛盾

-------int类型和包装类Integer类
int类型变量默认初始值为0
Integer类型默认初始值为null
注意:在javabean中创建对象模型的时候,编号id建议使用Integer类型,而不建议使用int类型
Integer b;
//将Integer转为int
int a = (int)b;

-------String类:不属于8大基本数据类型,并且该类被final所修饰
String类型用来表示一个字符串,底层实现实际上是一个字符数组
基本数据类型的包装类操作的是一个基本类型数据,
与基本数据类型的包装类不同,String也可以看做一个包装类,他操作的
是字符数组。

-------字符串创建时的内存分配 ----- 方法区中存在字符串常量池,池中放的都是字符数组
1.直接赋值方式创建字符串
  首先查找字符串常量池,有没有对应的字符串,如果没有,在常量池中创建,
  然后指向这个字符串对象,如果有就直接指向其地址值
2.new 的方式创建字符串
  首先在堆中开辟一块空间,查找字符串常量池,看有没有对应的
  字符数组,如果没有,在常量池中创建,然后指向
  如果有,直接指向.

面试题:String str = new String("abc");
       String str2 = new String("abc");
------执行第一条语句实际上创建了两个对象:堆内和字符串常量池中
      接着再执行第二条语句只会在堆中创建一个对象,然后指向字符串常量池中的字符数组
关键是后者公用前者在字符串常量池中创建的字符数组“abc”

例如如下程序:
  
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
String str4 = new String("abc");

那么:str1 == str2 :true
      str3 == str4 :false


0 0
原创粉丝点击