java基础总结

JDK和JRE的主要区别

JRE是用来运行java程序的,这个运行仅仅就只是运行,而不能进行编写之后再运行,但是假如你需要编写程序并将它能够编译执行,那么这个时候就需要你运用到JDK。

java和C++的区别

1.Java是不提供指针的,但是C++可以通过指针来对地址进行查询和定义,这样显得不是很安全。
2.java的类是单继承的,C++支持多重继承,但是java是不能支持多继承的,但是java当中的接口是可以多继承的。

private、default、protected、public的含义

private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
public : 对所有类可见。使用对象:类、接口、变量、方法

final、finally、finalize区别

final代表的是修饰类、方法、变量之后,最终不能被修改。finally表示的是try-catch语句当中必须要执行的代码语句块。finalize表示的就是是否可以被垃圾回收。当我们调用System.gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾

interface、Implements的理解

interface是接口,这个接口当中包含的是一些方法,并且接口之间可以进行继承,那就是这个接口a可以继承接口b,然后再接口a当中可以添加一些接口b当中没有的方法,但是接口a当中包含了接口b的方法。
Implements这个就是对于类当中如何对这个接口进行利用,一旦利用了class B implements Runnable{…}之后,Runnable当中的方法就可以被使用,下面来用代码进行详细的解释

interface Runner //定义接口
  {
                  int i=3;
                  public void start();
                 void run();
                 void stop();
         }
         interface Eater extends Runner //接口间可以继承
 {
                  public final static int j=4;
                 void openMouth();
                 void upAndDown();
                 void goIn();
         }
         class TT implements Eater //引用接口
{
                 public void start()
                 {
                         System.out.println("---------start()-------");
                 }
                 public void run()
                 {
                         System.out.println("---------run()-------");
                 }
                 public void stop()
                 {
                         System.out.println("---------stop()-------");
                 }
               public void openMouth()
                 {
                         System.out.println("---------openMouth()-------");
                 }
                 public void upAndDown()
                 {
                         System.out.println("---------upAndDown()-------");
                 }
                 public void goIn()
                 {
                         System.out.println("---------goIn()-------");
                 }
         }
         public class TestInterface {
             public static void main(String[] args) {
                 Runner tt = new TT();//接口的引用指向实现的对象
                 System.out.println(tt.i);
                 System.out.println(Runner.i);
                 tt.start();
                 Eater ee = new TT();
                 System.out.println(ee.j);
                 System.out.println(Eater.j);
                 ee.goIn();


             }
         }

下面显示的是运行的结果
在这里插入图片描述
一个类可以实现多个接口,但是实现的接口过程当中对应的不能实现两个互相继承的接口,例如A接口继承于B接口,那么类就不能同时实现A接口和B接口,而只需要实现A接口就可以了,因为A接口当中的方法,B接口也有。下面我来介绍一下我在运用接口的过程当中遭遇到的挫折

interface  Runner{
    int i=3;
    void start();
    public void run();
}
 interface  woqu{
    void wo1();
}
interface Eater extends Runner{
    void m2();
    void woshi();
}
interface  f2{
    public void woshi();
    public void woaini();
}
class TT  implements  Runner,f2{
    public void start(){
        System.out.println("我还是从前那个少年");
    }
    public void run(){
        System.out.println("开始运行了");
    }
    public  void wo(){
        System.out.println("sz");
    }
    public void woaini(){
        System.out.println("woshini");
    }
}

         public class TestInterface {
             public static void main(String[] args) {
                 Runner tt=new TT();//这个就是规定几口当中
                   f2 tt1=new TT();
tt1.woaini();
                 tt.start();


             }
         }

运行的结果是这样的:
在这里插入图片描述
于是我在这个当中加了接口当中对应的最后一个没有加入的方法来对这个接口进行覆盖
在这里插入图片描述
最后运行的结果就是这样了:
在这里插入图片描述

this和super的区别

这里我们需要明白的就是this是显示的是本类的方法或者常量,然而super()表示的是子类对于父类的方法或者常量的显示
super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
super()和this()均需放在构造方法内第一行。
尽管可以用this调用一个构造器,但却不能调用两个。
this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

static的详解

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。
被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。
只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。
用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。
static变量前可以有private修饰,表示这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用–废话),但是不能在其他类中通过类名来直接引用,这一点很重要。实际上你需要搞明白,private是访问权限限定,static表示不要实例化就可以使用,这样就容易理解多了。static前面加上其它访问权限关键字的效果也以此类推。
static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为:
类名.静态方法名(参数列表…)
类名.静态变量名
用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大,呵呵)。
1、static变量
 按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。
两者的区别是:
 对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
 对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
所以一般在需要实现以下两个功能时使用静态变量:
 在对象之间共享值时
 方便访问变量时
2、静态方法
静态方法可以直接通过类名调用,任何的实例也都可以调用,
因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。
因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!!
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
例如为了方便方法的调用,Java API中的Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。
静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的
3、static代码块
 static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。例如:

public class Test5 { 
  private static int a; 
  private int b; 
  static{ 
    Test5.a=3; 
    System.out.println(a); 
    Test5 t=new Test5(); 
    t.f(); 
    t.b=1000; 
    System.out.println(t.b); 
  } 
  static{ 
    Test5.a=4; 
    System.out.println(a); 
  } 
  public static void main(String[] args) { 
    // TODO 自动生成方法存根 
  } 
  static{ 
    Test5.a=5; 
    System.out.println(a); 
  } 
  public void f(){ 
    System.out.println("hhahhahah"); 
  } 
}  

运行结果:
3
hhahhahah
1000
4
5
 利用静态代码块可以对一些static变量进行赋值,最后再看一眼这些例子,都一个static的main方法,这样JVM在运行main方法的时候可以直接调用而不用创建实例。
4、static和final一块用表示什么
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。
有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。
声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。声明为static的方法有以下几条限制:

它们仅能调用其他的static 方法。

它们只能访问static数据。

它们不能以任何方式引用this 或super(关键字super 与继承有关,在下一章中描述)。
如果你需要通过计算来初始化你的static变量,你可以声明一个static块,Static 块仅在该类被加载时执行一次。下面的例子显示的类有一个static方法,一些static变量,以及一个static 初始化块:

// Demonstrate static variables,methods,and blocks. 
class UseStatic { 
  static int a = 3; 
  static int b; 
  static void meth(int x) { 
    System.out.println("x = " + x); 
    System.out.println("a = " + a); 
    System.out.println("b = " + b); 
  } 
  static { 
    System.out.println("Static block initialized."); 
    b = a * 4; 
  } 
  public static void main(String args[]) { 
    meth(42); 
  } 
} 

一旦UseStatic 类被装载,所有的static语句被运行。首先,a被设置为3,接着static 块执行(打印一条消息),最后,b被初始化为a*4 或12。然后调用main(),main() 调用meth() ,把值42传递给x。3个println ( ) 语句引用两个static变量a和b,以及局部变量x 。
注意:在一个static 方法中引用任何实例变量都是非法的。
下面是该程序的输出:

Static block initialized.
x = 42
a = 3
b = 12

在定义它们的类的外面,static 方法和变量能独立于任何对象而被使用。这样,你只要在类的名字后面加点号运算符即可。例如,如果你希望从类外面调用一个static方法,你可以使用下面通用的格式:

classname.method( )
这里,classname 是类的名字,在该类中定义static方法。可以看到,这种格式与通过对象引用变量调用非static方法的格式类似。一个static变量可以以同样的格式来访问——类名加点号运算符。这就是Java 如何实现全局功能和全局变量的一个控制版本。
下面是一个例子。在main() 中,static方法callme() 和static 变量b在它们的类之外被访问。

class StaticDemo { 
  static int a = 42; 
  static int b = 99; 
  static void callme() { 
    System.out.println("a = " + a); 
  } 
  } 
  class StaticByName { 
    public static void main(String args[]) { 
    StaticDemo.callme(); 
    System.out.println("b = " + StaticDemo.b); 
  } 
} 

下面是该程序的输出:
a = 42
b = 99
static成员是不能被其所在class创建的实例访问的。
如果不加static修饰的成员是对象成员,也就是归每个对象所有的。
加static修饰的成员是类成员,就是可以由一个类直接调用,为所有对象共有的。

在类中定义一个无参的构造方法的作用是什么

为什么要定义一个无参的构造方法呢,因为当子类没有用super()来调用父类的方法的时候,这个时候当父类没有构造方法的时候,编译就会出错,因为java程序在父类当中找不到没有参数的构造方法可供执行。解决方法是在父类当中加上一个无参的构造方法。

内部类

内部类包括了四种:成员内部类、局部内部类、匿名内部类和静态内部类

静态内部类

定义在类内部的静态类,就是静态内部类。


public class Outer {

    private static int radius = 1;

    static class StaticInner {
        public void visit() {
            System.out.println("visit outer static  variable:" + radius);
        }
    }
}

静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量;静态内部类的创建方式,new 外部类.静态内部类(),如下:

Outer.StaticInner inner = new Outer.StaticInner();
inner.visit();

成员内部类

定义在类内部,成员位置上的非静态类,就是成员内部类。

public class Outer {

    private static  int radius = 1;
    private int count =2;
    
     class Inner {
        public void visit() {
            System.out.println("visit outer static  variable:" + radius);
            System.out.println("visit outer   variable:" + count);
        }
    }
}

成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类(),如下:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.visit();

局部内部类

定义在方法中的内部类,就是局部内部类。

public class Outer {

    private  int out_a = 1;
    private static int STATIC_b = 2;

    public void testFunctionClass(){
        int inner_c =3;
        class Inner {
            private void fun(){
                System.out.println(out_a);
                System.out.println(STATIC_b);
                System.out.println(inner_c);
            }
        }
        Inner  inner = new Inner();
        inner.fun();
    }
    public static void testStaticFunctionClass(){
        int d =3;
        class Inner {
            private void fun(){
                // System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
                System.out.println(STATIC_b);
                System.out.println(d);
            }
        }
        Inner  inner = new Inner();
        inner.fun();
    }
}

定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类(),如下:

 public static void testStaticFunctionClass(){
    class Inner {
    }
    Inner  inner = new Inner();
 }

匿名内部类

匿名内部类就是没有名字的内部类,日常开发中使用的比较多。

public class Outer {

    private void test(final int i) {
        new Service() {
            public void method() {
                for (int j = 0; j < i; j++) {
                    System.out.println("匿名内部类" );
                }
            }
        }.method();
    }
 }

//匿名内部类必须继承或实现一个已有的接口

 interface Service{
    void method();
}

除了没有名字,匿名内部类还有以下特点:

匿名内部类必须继承一个抽象类或者实现一个接口。
匿名内部类不能定义任何静态成员和静态方法。
当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
匿名内部类创建方式:


new/接口{ 
  //匿名内部类实现部分
}

内部类的优点

我们为什么要使用内部类呢?因为它有以下优点:

一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
内部类不为同一包的其他类所见,具有很好的封装性;
内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
匿名内部类可以很方便的定义回调。
内部类有哪些应用场景
一些多算法场合
解决一些非面向对象的语句块。
适当使用内部类,使得代码更加灵活和富有扩展性。
当某个类除了它的外部类,不再被其他的类使用时。
局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?
局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final呢?它内部原理是什么呢?

先看这段代码:

public class Outer {

    void outMethod(){
        final int a =10;
        class Inner {
            void innerMethod(){
                System.out.println(a);
            }

        }
    }
}

以上例子,为什么要加final呢?是因为生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。

内部类相关,看程序说出运行结果

public class Outer {
    private int age = 12;

    class Inner {
        private int age = 13;
        public void print() {
            int age = 14;
            System.out.println("局部变量:" + age);
            System.out.println("内部类变量:" + this.age);
            System.out.println("外部类变量:" + Outer.this.age);
        }
    }

    public static void main(String[] args) {
        Outer.Inner in = new Outer().new Inner();
        in.print();
    }

}

运行结果:

局部变量:14
内部类变量:13
外部类变量:12

重载和重写的区别

重写主要是利用的是继承的方式,让子类继承父类,在当中进行的重写对类进行的构造,当父类当中的方法和主类当中的方法相同的话,这个时候就需要用到super方法了,即为super.方法名。重载呢,就是改变了方法的一些参数,不允许具有相等的参数,并且重载可以改变返回类型

==和equals的区别是什么

==:它的作用是判断两个对象的地址是不是相等。即判断两个对象是不是同一个对象。
equals:它的作用是判断两个对象是不是相等。但它一般有两种使用情况
情况1:类没有覆盖方法,则通过equals()比较该类的两个对象的时候,等价于通过’= ="号来比较这两个对象
情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来判断两个对象的内容是否相等。
如下所示:

 public class TestInterface {
             public static void main(String[] args) {
                StringBuilder a=new StringBuilder("wo");
                StringBuilder b=new StringBuilder("wo");
                String a1=new String("ni");
                String a2=new String("ni");
                 System.out.println(a1==a2);//由于a1和a2是两个不同的对象,所以地址不同 false
                 System.out.println(a1.equals(a2));//由于a1和a2内容是相同的 ture
                 System.out.println(a==b);//false
                 System.out.println(a.equals(b));//false


             }
         }

hashCode与eauals(重要)

什么是hashCode ?
hashCode存在于每一个类当中,也就是说,你每一个创建的对象都有它对应的hashcode,这样当你把对象加入到HashSet之后,HashSet就根据你的Hash值来对这个位置进行判断
HashCode()和equals()的比较,为什么二者要连用?
在当你要把一个对象添加进入堆的时候,你需要防止添加进入重复的对象,这个时候你就需要先判断二者的HashCode()是否相同,如果不相同,那么他们的内容是肯定不相同的,这个就是一个首要的判断,当你发现两个对象的HashCode相同的话,那么就比较他们是否内容相同,因此二者是要连用的,如果内容相同,那么就不加入相同的类进入堆当中。
如下:

`public class TestInterface {
             public static void main(String[] args) {

             String a4="woshishui";
             String a5="woshishui";
             int w1=a5.hashCode();
             int w=a4.hashCode();
                 System.out.println(w);
                 System.out.println(w1);
                 System.out.println(a4.equals(a5));

             }
         }`

对应的结果是这样的:
在这里插入图片描述

Java包

JDK 中常用的包有哪些

java.lang:这个是系统的基础类;
java.io:这里面是所有输入输出有关的类,比如文件操作等;
java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
java.net:这里面是与网络有关的类;
java.util:这个是系统辅助类,特别是集合类;
java.sql:这个是数据库操作的类。
import java和javax有什么区别
刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说使用。然而随着时间的推移,javax 逐渐的扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。

所以,实际上java和javax没有区别。这都是一个名字。

java 中 IO 流分为几种?

按照流的流向分,可以分为输入流和输出流;
按照操作单元划分,可以划分为字节流和字符流;
按照流的角色划分为节点流和处理流。
Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

BIO,NIO,AIO 有什么区别?

简答

BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
详细回答

BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

反射

什么是反射机制?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

静态编译和动态编译

**静态编译:**在编译时确定类型,绑定对象
**动态编译:**运行时确定类型,绑定对象
反射机制优缺点
优点: 运行期类型的判断,动态加载类,提高代码灵活度。
缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。
反射机制的应用场景有哪些?
反射是框架设计的灵魂。

在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性

String为什么是不可变的呢?

简单来说就是String类利用了final修饰的char类型数组存储字符

private final char value[];

String真的是不可以变的吗?

如果别人问你这个问题的话,回答不可变就行了,但是,其实String是可以变的,只是变的方式不同而已。

String str="Hello";
str=str+"world";
System.out.println("str="+str)

结果:产生的是Hello world,但是这个结果是因为str由原来指向”Hello“的地址指向了”hello Word“的地址,也就是说内存新开辟了一个空间。

String str="i"与String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,java虚拟机会将其分配到常量池中;而String str=new String(“i”)则会被分配到堆内存中。

在使用 HashMap 的时候,用 String 做 key 有什么好处?

HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

int和Integer之间的关系

public static void main(String[] args) {
    Integer a = new Integer(3);
    Integer b = 3;  // 将3自动装箱成Integer类型
    int c = 3;
    System.out.println(a == b); // false 两个引用没有引用同一对象
    System.out.println(a == c); // true a自动拆箱成int类型再和c比较
    System.out.println(b == c); // true

    Integer a1 = 128;
    Integer b1 = 128;
    System.out.println(a1 == b1); // false

    Integer a2 = 127;
    Integer b2 = 127;
    System.out.println(a2 == b2); // true
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值