快速导航
Java基础面试题
何为编程
对于计算机来说,编程就是为了解决某个问题而用某种程序设计语言设计程序,并得到结果的过程
对于人来说,编程就是人将解决问题的方法、手段、思路等以计算机能理解的方式告诉计算机,以便计算机能按照人的指令一步步去工作,完成特定任务的,人机交互的过程。 什么是Java
Java版本
Java ME/j2ME/Java 2 Platform Micro Edition
Java SE/j2SE/Java 2 Platform Enterprise Edition
标准版本,桌面、服务器、嵌入环境、和实时环境的java应用程序
Java SE 包含了支持 Java Web 服务开发的类,并为Java EE和Java ME提供基础。
Java EE/j2EE/J2EE,Java 2 Platform Enterprise Edition
企业版,健壮、安全、可伸缩的服务器端Java应用程序,企业级面向服务体系结构和Web2.0应用 JVM、JRE和JDK的关系
JDK Java开发工具包
包括编译工具(javac.exe)、打包工具(jar.exe)等
什么是跨平台性?原理是什么
实现原理:Java程序是通过不同平台的JVM运行的,只要安装不同的JVM即可 Java语言的特点
什么是字节码?采用字节码的最大好处是什么
java源代码结果虚拟机编译后产生的.class文件,不面向处理器只面向虚拟机
好处
解决传统解释型语言执行效率低的问题 又保留了解释型语言可移植的特点
运行顺序
Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中解释器----->机器可执行的二进制机器码---->程序运行。
什么是Java程序的主类?应用程序和小程序的主类有何不同?
一个程序可以有多个类,但只能有一个主类
Java中这个类指的是包含main()f方法的类,是执行程序的入口点
应用程序和小程序的主类的不同
Java小程序中主类是继承自JApple/Applet的子类 小程序的主类必须是public类 Java应用程序与小程序之间有那些差别?
Apple小程序没有mian方法,主要嵌在网页运行,也就是init()或者run()启动 Java和C++的区别
不同
JAVA单继承、C++支持多重继承;JAVA通过接口实现多继承
Oracle JDK 和 OpenJDK 的对比
Oracle JDK版本将每三年发布一次,而OpenJDK版本每三个月发布一次;
OpenJDK 是一个参考模型并且是完全开源的,而Oracle JDK是OpenJDK的一个实现,并不是完全开源的;
Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎相同,但Oracle JDK有更多的类和一些错误修复。
在响应性和JVM性能方面,Oracle JDK与OpenJDK相比提供了更好的性能;
Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本;
Oracle JDK根据二进制代码许可协议获得许可,而OpenJDK根据GPL v2许可获得许可。
数据类型
Java有哪些数据类型
基本数据类型
字符类型 char
2字节(一个中文字)0~65535
char类型也可以存数字,但0~127以内的数字会从ASCII码表查出的对字符显示 128~65535这些范围内的数字也可以保存,但是eclipse一般显示为?
* char类型的的数组在底层代码中做了处理,可以直接打印数组的具体元素
* 其他需要 Arrays.toString( ) 否则打印出地址值
常用的转换关系:
1 Byte = 8 bits (1字节 = 8位)
1 KB = 1024 Bytes 1 MB = 1024 KB 1 GB = 1024 MB
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗
short s1 = 1; s1 = s1 + 1
由于1为int类型,所以S1+1也是int型,需要强制类型转换才能赋值给short类型的S1
short s1 = 1; s1 += 1
可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。
运算规则
byte,short,char三种比int小的整数,运算时会先自动转换成int
float f=3.4;是否正确
错误,3.4没有F尾缀,属于double类型,下转型或者说窄化会造成精度损失
解决方法:float f=3.3F 或者强制转换 float f=(float)3.4
Math.round(11.5) 等于多少?Math.round(-11.5)等于多少 ?
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。
用最有效率的方法计算 2 乘以 8(二进制)
2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)。
switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上
目前支持的有 byteshortintcharString枚举类型
面向对象概述
面向对象和面向过程的区别
面向过程:
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
面向对象:
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
面向对象三大特性
封装
隐藏细节 只给出使用信息、使用方式,比如类和方法
分类
使用private关键字进行封装
属性封装
右键空白处->Generate->Getter and Setter->选中subject属性->OK 自动生成一个公共的方式,供外界操作封装的属性的属性值
类的封装
在公共方法clean()中调用封装方法eat()的功能
继承
子类可以拥有父类的所有功能(属性/方法),并在无需重新编写原来的类的情况下对这些功能进行扩展。
特殊性
增加父类没有的变量和方法 或者修改父类已有的变量和方法
特点
Java只支持单继承
一个儿子只有一个爸爸 单继承(Java只支持单继承 多重继承是通过一个类继承多个接口实现的)
子类继承父类后,可以使用父类所有的非私有资源 私有资源也被继承 但是因为访问受限(private)不能使用
父类的私有成员也会被继承,但由于私有限制访问,所以子类不能使用父类的私有资源
继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
可以在不修改父类功能的【满足OCP原则】前提下,在子类中,重写继承过来的这个方法
重写需要满足的规则:两同 两小 一大,我们可以在重写的方法上加@Override注解验证是否写对
像是is a的关系
继承要求子类必须是父类的一种下属属性,依赖强,强耦合
继承的好处与坏处
好处
提高了代码的复用性(多个类相同的成员可以放在同一个类中)
提高了代码的维护性(如果方法的代码需要修改,只修改一处即可)
坏处
继承让类与类建立了关系,类的耦合性增强
当父类发生变化时,子类实现也不得不跟着变化,削弱了子类的独立性
super
我们可以把super看作是父类的对象:Father super = new Father();
1.当父类的成员变量与子类的变量同名时,使用super指定父类的成员变量
子类在创建对象时默认调用父类的构造方法 因为子类构造函数时第一行默认存在super();--表示调用父类的无参构造
父类没有无参构造时,可以通过super(参数)调用父类的其他构造函数 子类必须调用一个父类的构造函数,无论有参还是无参必须选择一个
构造方法不能被继承 因为语法原因:要求构造方法名字必须是本类类名,不能在子类中出现一个父类名字的构造方法
2.使用super在子类构造方法的第一行调用父类构造方法的功能
多态
不同的子类对象调用相同的方法产生不同的结果
分类
静态多态性
编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数
动态多态性
在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性
实现
方法重载
一个类中有多个相同名字的方法 但这些方法的参数不同 参数个数或者参数类型不同
优点
多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
使用
多态对象把自己看做是父类类型
成员方法: 由于存在重写现象,所以使用的是子类的,但是定义看父类的
口诀
父类引用指向子类对象
创造出来子类的地址值,交给父类类型的引用变量来保存
编译看左边,运行看右边
必须在父类在定义这个方法,才能通过编译,因为多态对象认为自己时父类类型 必须在子类中重写父类的方法 才能满足多态 实际干活的是子类
抽象
抽象是将一类对象的共同特征总结出来构造类的过程
包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
常用API
String相关
字符型常量和字符串常量的区别
形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符
含义上: 字符常量相当于一个整形值(ASCII值),可以参加表达式运算 字符串常量代表一个地址值(该字符串在内存中存放位置)
占内存大小 字符常量只占两个字节 字符串常量占若干个字节(至少一个字符结束标志)
什么是字符串常量池?
字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。
String 是最基本的数据类型吗
不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype)
String有哪些特性
不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。
常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。
final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。
String为什么是不可变的?
简单来说就是String类利用了final修饰的char类型数组存储字符
String真的是不可变的吗?
1) String不可变但不代表引用不可以变
实际上,原来String的内容是不变的,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串。
2) 通过反射是可以修改所谓的“不可变”对象
用反射可以访问私有成员, 然后反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。但是一般我们不会这么做
是否可以继承 String 类
String 类是 final 类,不可以被继承。
String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
String s = new String(“xyz”);创建了几个字符串对象
两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。
如何将字符串反转?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
数组有没有 length()方法?String 有没有 length()方法
数组没有 length()方法 ,有 length 的属性。
Javascript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。
String 类的常用方法都有那些?
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
在使用 HashMap 的时候,用 String 做 key 有什么好处?
HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。
String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的
可变性
String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
线程安全性
String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
性能
每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结
单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
Date相关
包装类相关
int 和 Integer 有什么区别
java为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型(wrapper class),int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
Java 为每个原始类型提供了包装类型:
原始类型: boolean,char,byte,short,int,long,float,double
包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
Integer a= 127 与 Integer b = 127相等吗
如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false 常见区分对比
面向对象与面向过程的区别
面向过程PO:这种编程思想强调的是过程,凡事亲力亲为
优点:性能比面向对象要高,因为类调用的时候需要实例化,资源消耗更大,比如单片机、嵌入式开发、Linux/Unix一般是面向过程开发,性能是最重要的因素
OOP将数据封装于类中 完全面型对象 强调结果
优点:易维护易扩展易复用,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使得系统更加灵活,更加易于维护。
构造函数
构造方法
构造函数的结构及注意事项
1、结构:【public 类名([参数类型1 参数名1,参数类型2 参数名2..... ])】
3、一般在创建一个类的时候,如果创建的类没有构造函数程序会自动创建一个默认的无参构造函数,当你在类中已经写有构造函数,那么默认无参构造函数将会被覆盖,也就是不存在。
重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载:发生在同一个类中,
方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,
重写:发生在父子类中,
方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。
方法重写的访问权限只能扩大(权限大小:public > protected > 缺省 > private),而方法重载对权限无要求。
两同:子类方法的 方法名与参数列表 和父类方法的相同
一大:子类方法的 方法修饰符权限 >= 父类方法的
两小:子类方法的返回值类型 <= 父类方法的返回值类型 子类方法抛出的异常类型 <= 父类方法抛出的异常类型
注意:这里所说的<=是指子类方法的返回值类型是父类返回值类型的子类或者与父类的返回值类型一致,如果父类方法的返回值类型是void,子类保持一致即可
this与super区别
this主要作用:
1、在本类中作为对象调用属性成员变量,在属性名与局部变量参数名相同时,需要用this来指定成员变量属性,否则调用的是局部变量或者参数
2、调用构造函数
this关键字调用构造函数,必须写在构造函数第一行
3、返回类的引用。如return this来返回某个类的引用。此时this关键字就代表类的名称
4、普通的直接引用,this相当于指向当前对象本身
super可以理解为指向自己父类的一个指针,这个父类指的是离自己最近的一个父类
普通的直接引用
与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。
子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分
引用父类构造函数
子类在创建对象时默认调用父类的构造方法 因为子类构造函数时第一行默认存在super();--表示调用父类的无参构造
父类没有无参构造时,可以通过super(参数)调用父类的其他构造函数 子类必须调用一个父类的构造函数,无论有参还是无参必须选择一个
this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
构造方法不能被继承 因为语法原因:要求构造方法名字必须是本类类名,不能在子类中出现一个父类名字的构造方法
区别
super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
super()和this()均需放在构造方法内第一行。
尽管可以用this调用一个构造器,但却不能调用两个。
this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
静态变量和实例变量的区别
在语法定义上的区别:
静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:
静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
代码块
分类
静态代码块
作用:用于需要第一时间加载,并且只加载一次的资源,常用来初始化
特点: 被static修饰,位置在类里方法外,属于静态资源,随着类的加载而加载,优于对象加载
构造代码块(成员变量位置)
执行时机 每次创建对象都会执行构造代码块,并且优于构造函数执行
局部代码块(局部变量位置)
作用 用于控制变量的执行范围,变量的作用范围越小越好
三种代码块的比较
静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
构造代码块:在创建对象时会自动调用,每次创建对象都会被调用,提取构造共性
运行顺序
静态代码块->构造代码块->构造方法->普通方法->局部代码块
2.创建对象时,也会触发构造代码块,并且构造代码块优先于构造方法执行
4.如果普通方法里有局部代码块,才会触发对应的局部代码块
抽象类与接口的区别 背过
抽象类和接口的对比
从设计层面来说:抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为规范
抽象类用来捕捉子类的通用特性,接口是抽象方法的集合
接口会为方法自动拼接public abstract,还会为变量自动拼接public final static
选择原则
行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量少用抽象类。
选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用的功能。
StringBuilder和StringBuffer的区别
都是用来拼接字符串的
1.在线程安全上 :
–StringBuffer是旧版本就提供的,线程安全的。
–StringBuilder是jdk1.5后产生,线程不安全的。
2. 在执行效率上,StringBuilder > StringBuffer > String
3.源码体现:本质上都是在调用父类抽象类AbstractStringBuilder来干活,只不过Buffer把代码加了同步关键字,使得程序可以保证线程安全问题。StringBuffer在append方法上增加了sycronize线程锁
小结:
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。
String
特点:创建之后长度内容是不可变的,每次拼接字符串,都会产生新的对象
如果是直接“ ” 或者字符串常量拼接产生的,保存在字符串常量池中
创建方式:
String() String(String s) String(char[] c) String(byte[] b) String s = “abc”;
优缺点:
优点:String类提供了丰富的关于操作字符串的方法,比如:拼接、获取对应下标处的字符、截取子串等等
String转StringBuilder:
String s = “abc”; StringBuilder sb = new StringBuilder(s);
==和equals的区别 面试必问
1.当使用= =比较时,如果相比较的两个变量是引用类型,那么比较的是两者的物理地值(内存地址),如果相比较的两个变量都是数值类型,那么比较的是具体数值是否相等。
2.当使用equals()方法进行比较时,比较的结果实际上取决于equals()方法的具体实现
任何类都继承自Object类,因此所有的类均具有Object类的特性,比如String、integer等,他们在自己的类中重写了equals()方法,此时他们进行的是数值的比较,而在Object类的默认实现中,equals()方法的底层是通过==来实现的。
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
equals()和hashCode()逻辑上要保持一致 要重写全部重写,要不全部不重写
如果不重写:hashCode()的哈希码根据地址值生成 equals()底层使用==比较两个对象的地址值
如果重写了:hashCode()的哈希码根据重写传入的属性值生成 equals()比较的是重写后类型 + 所有属性与属性值
API
Sting
String API总结
继承的方法 写的不太对
int hashCode() 返回此字符串的哈希码。
boolean equals(Object anObject) 将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString() 返回此对象本身(它已经是一个字符串!)。
String toUpperCase() 所有字符都转换为大写。
String toLowerCase() 所有字符都转换为小写
boolean startsWith(String prefix) 测试此字符串是否以指定的元素开头。
boolean endsWith(String suffix) 测试此字符串是否以指定的字符串结束。
char charAt(int index) 返回指定索引/下标处的 char 值/字符
int indexOf(String str) 返回指定字符在此字符串中第一次出现处的索引。
int lastIndexOf(String str) 返回指定字符在此字符串中最后一次出现处的索引。
String concat(String str) 将指定字符串连接/拼接到此字符串的结尾,注意:不会改变原串
String[] split(String regex) 根据给定元素来分隔此字符串。
String trim() 返回去除首尾空格的字符串
byte[] getBytes() 把字符串存储到一个新的 byte 数组中
String substring(int beginIndex) 返回一个新子串,从指定下标处开始,包含指定下标
String substring(int beginIndex, int endIndex) 返回一个新子串,从执定下标开始,到结束下标为止,但不包含结束下标
static String valueOf(int i) 把int转成String
Object
常用方法介绍
toString()
本方法用于返回对应对象的字符串表示
子类重写了父类Object中的toString()以后,不再打印对象的地址值,子类重写了toString()以后:打印是对象的类型+属性+属性值
hashCode()
用于返回对应对象的哈希码值
hashCode() 作用 根据对象地址值返回相应对象的int类型的哈希码值目的 让不同的对象返回不同的哈希码值,用来区分对象
equals()
用于指示其他某个对象是否与当前对象”相等”
==比较的是值 基本类型比较的是字面值 引用类型比较的是引用类型变量引用地址值
Object中的equals()默认使用==进行比较,比较的结果实际上取决于equals()方法的具体实现
equals()和hashCode()逻辑上要保持一致 要重写全部重写,要不全部不重写
如果不重写:hashCode()的哈希码根据地址值生成 equals()底层使用==比较两个对象的地址值
如果重写了:hashCode()的哈希码根据重写传入的属性值生成 equals()比较的是重写后类型 + 所有属性与属性值
static
特点
3.静态资源随着类的加载而加载,最先加载,优先于对象进行加载
7.静态区域内不允许使用this与super关键字
static
static存在的主要意义
形成静态代码块来优化程序性能
static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
独特之处
被static修饰的变量或者方法独立于任何对象,而被类的实例对象所共享
静态资源随着类的加载而加载,最先加载,优先于对象进行加载进行初始化,可以再次赋值
static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!
被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,可以通过类名直接调用。
注意事项
非静态可以访问静态、非静态的资源;静态资源只能访问静态资源
HashMap与Hashtable的区别
产生时间
Hashtable在一开始java发布时就提供的键值映射数据结构 HashMap产生于JDK1.2 但是Hashtable基本上已经被弃用了,而Hash应用广泛,一方面是因为Hashtable是线程安全的效率比较低,可能是因为Hashtable没有遵循驼峰命名法吧
继承的父类不同
HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary(已经被废弃)类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口
对外提供的接口不同
Hashtable比HashMap多提供了elments() 和contains() 两个方法。
elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。
contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。
对Null key 和Null value的支持不同
Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明。
当key为Null时,调用put() 方法,运行到下面这一步就会抛出空指针异常。因为拿一个Null值去调用方法了。
当value为null值时,Hashtable对其做了限制,运行到下面这步也会抛出空指针异常。
HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
线程安全性不同
Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步
HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。具体的原因在下一篇文章中会详细进行分析。使用HashMap时就必须要自己增加同步处理,
虽然HashMap不是线程安全的,但是它的效率会比Hashtable要好很多。这样设计是合理的。在我们的日常使用当中,大部分时间是单线程操作的。HashMap把这部分操作解放出来了。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
ArrayList和linkedlist
相同
元素有下标,有序,允许存放重复元素(List本身特点)
不同
1. ArrayList是实现了基于动态数组的数据结构,而linkedList是基于链表的数据结构;
3. 对于随机访问get和set,ArrayList要优于linkedList,因为linkedList要移动指针;
4. 对于添加和删除操作add和remove,一般大家都会说linkedList要比ArrayList快,因为ArrayList要移动数据。但是实际情况并非这样,对于添加或删除,linkedList和ArrayList并不能明确说明谁快谁慢.
所以当插入的数据量很小时,两者区别不太大,当插入的数据量大时,大约在容量的1/10之前,linkedList会优于ArrayList,在其后就劣与ArrayList,且越靠近后面越差。所以个人觉得,一般首选用ArrayList,由于linkedList可以实现栈、队列以及双端队列等数据结构,所以当特定需要时候,使用linkedList,当然咯,数据量小的时候,两者差不多,视具体情况去选择使用;
当数据量大的时候,如果只需要在靠前的部分插入或删除数据,那也可以选用linkedList,反之选择ArrayList反而效率更高。
wait()与sleep()的区别
wait()来自Object类 sleep()来自Thread类
调用sleep()方法,线程不会释放对象锁,调用wait()方法线程会释放线程锁
sleep()睡眠后不会让出系统资源,wait()会让出,并让其他线程占用cpu
sleep()需要制定一个睡眠时间,时间一到自动唤醒,而wait()需要notify()或者notifyAll()使用
进程与线程
1. 什么是进程?什么是程序?有什么区别?
进程:给程序加入了时间的概念,不同的时间进程有不同的状态
2. 什么是并行?什么是串行?什么是并发?
串行:是指同一时刻一个CPU只能处理一件事,类似于单车道
并行:相对来说资源比较充足,多个CPU可以同时处理不同的多件事,类似于多车道
并发:相对来说资源比较紧缺,多个进程同时抢占公共资源,比如多个进程抢占一个CPU
3. 什么是线程?线程与进程有什么关系?
一个进程可以拥有多个线程,当然,也可以只拥有一个线程,只有一个线程的进程被称作单线程程序
注意:每个线程也有自己独立的内存空间,当然也有一部分公共的空间用于保存共享的数据
结论:线程的执行具有随机性,我们控制不了,是由OS底层的算法来决定的
常见数据结构
简单说一下常见的数据结构
栈Stack
又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。
栈结构对元素的存取有如下要求:
先进后出(也就是说,栈中越早存进去的元素,就越在最下面)
1)压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
2)弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。
队列queue
队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
先进先出(也就是说,最先存进去的元素,是可以最先取出的)
数组Array
是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一列火车,从1号车厢到最后一节车厢,每节车厢都有自己的固定编号,乘坐火车的人可以通过车厢号快速找到自己的位置。
增删元素慢:
我们指定一个索引增加元素,不能修改原数组的长度,而是需要创建一个新长度的数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。
我们指定一个索引删除元素:不能修改原数组的长度,而是需要创建一个新长度的数组,把原数组元素根据索引复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。
链表linkedList
是一系列节点Node(链表中每一个元素称为节点)组成,节点可以在运行时动态生成。每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。我们常说的链表结构有单向链表与双向链表。
单向链表
我们可以简单理解成:链表结构对元素的存取有如下要求:多个节点之间,通过地址进行连接。
查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
红黑树
二叉树
二叉树BinaryTree:每个节点不超过2的有序树(tree)
我们可以简单理解成生活的树的结构,只不过每个节点上都最多只能有两个子节点。
二叉树是每个节点最多有两个子树的树结构。顶上的叫根节点,两边被称作“左子树”和“右子树”。
红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。红黑树的速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍
红黑树的特点:
任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同