JDK=JRE+开发工具包;JRE=JVM+核心类库
main方法作用
一个文件中可以有多个类,但是只能有一个public类,且该类名和文件名一致;但是一个类中有多个不同类时,就会产生多个.class文件。所以.class文件名应该是:类名+.class 并不一定就是.java文件名
如果在一个Java源文件中定义了1个公共类以及三个普通的类,那么编译该Java源文件会产生_个字节码文件。java是区分大小写的,但是window不区分大小写;一个java文件中,有若干个不区分大小写的“同名”类,在window环境下将会最后只有一个.class文件,编译哪个就产生哪个.class文件。但是会运行java文件中最后一个类的内容,结果也是最后一个类的结果。
java文件中有几个类就有几个.class文件(不准确,一般情况下是这样)
带包编译
javac -d . JavaDemo.java
带包运行
java cn.tedu.demo.Demo
关键字:
关键字指的就是电脑语言中事先定义好,有其独特意义的标识符,专门提供给电脑语言识别的词语,所以它不能作为变量名、方法名、类名、包名或参数名等等。
在java中,总共有51个关键字,2个保留字,其中"const"和"goto"是其他电脑语言的关键字,所以在java当中没有具体含义,而且都是小写。
abstract |
assert |
boolean |
break |
byte |
case |
catch |
char |
class |
const |
continue | default | do | double | else |
enum | extends | final | finally | float |
for | goto | if | implements | import |
instanceof | int | interface | long | native |
new | package | private | protected | public |
return | strictfp | short | static | super |
switch | synchronized | this | throw | throws |
transient | try | void | volatile | while |
访问控制:private protected public
定义类、接口、抽象类和实现接口、继承类的关键字、实例化对象:class abstact interface extends implements new
修饰方法、类、属性和变量:static final super this native strictfp synchronized transient volatile
程序控制语句:break continue return do while if else for
instanceof switch case defautl
错误处理:try catch final throw throws assert
包相关:import package
基本类型:boolean byte char double float int long short
null true false enum
变量引用:super this void
保留字:const goto
https://baike.baidu.com/item/java%E5%85%B3%E9%94%AE%E5%AD%97/5808816?fr=aladdin
标识符:由数字、字母、下划线和$组成;不能使用关键字;大小写敏感;不能数字开头;见名知意。
驼峰命名法:类名每个单词首字母手写;变量名和方法名首个单词首字符小写,后续大写。
1.字面值常量
1.字符串常量 "hello" "1"
2.字符常量 'a' '2'
3.整数常量 1 100 1000
4.小数常量 1.0 0.98
5.布尔常量 true、false
6.空常量 null
2.自定义常量。如静态常量
几种自定义常量的方法:https://blog.csdn.net/rlnLo2pNEfx9c/article/details/81277528
进制:二进制(满二进一、0b或0B开头)、八进制(满八进一、0开头)、十进制(满十进一)、十六进制(满十六进一、0x或0X开头);
进制转换:
定义一个变量:数据类型 变量名 变量值;
Java语言支持的变量类型有:
注意:
先定义后使用;
在哪定义在哪使用;
先赋值后使用;
数据类型:基本数据类型(8个)和引用数据类型
基本数据类型:
数值型:
整数型:
byte:1个字节
short:2个字节
int:4个字节
long:8个字节,以上默认皆为0
小数型:
double8个字节,默认为0.0
float4个字节,默认为0.0
字符型:char4个字节,默认为\u0000
布尔型;boolean,默认为false
引用数据类型:类、接口和数组,默认值皆为null.
运算符:
算数运算:+ - * / % ++ --
关系运算:> < >= <= == !=
赋值运算:= += -= *= /= %= &= |= ^= <<= >>= >>>=
逻辑运算:$ | && || ^ ~
位运算:& | ^ ~ >> << >>>
三元运算:
优先级:() ~ ++ -- ! 算术 << >> >>> 关系 逻辑 & | ^ 三元 赋值
流程控制:
顺序结构:
选择结构:if else/switch-case(switch()的值类型:byte/short/char/int,从JDK1.5开始允许使用枚举,从JDK1.7开始允许使用String)
循环结构:
while:适用于次数不定或者变化不规律的情况
do while:至少执行一次循环体
for:条件明确;次数明确
break:跳出当前层循环,没有下次循环;可用于选择和循环结构
continue:跳出本次循环,下次循环继续;只能用于循环结构
break是结束整个循环体,continue是结束单次循环
面向对象和面向过程比较:
面向过程注重事情的每一步流程;面向对象只要拥有对象,就可以调用对象身上的方法;
简单事物优先用面向过程;复杂事物优先使用面向对象;
面向过程是面向对象的基础;
类和对象:
类的基本结构
属性:对象数据的描述
方法:对象的行为
构造方法:用于实例化对象
内部类:在类中声明的类(inner class)
块:分静态块与实例块
类的声明:(访问权限修饰符public.default(可忽略不写,为默认))(修饰符final.abstract.synchronized)class 类名{ 类体 }
类的作用:类就是一个模板,定义多个对象共同的属性和方法
对象:
“按照通俗的说法,每个对象都是某个类(class)的一个实例(instance),这里,‘类’就是‘类型’的同义词。”---引自《Java编程思想》
类是对某一类事或物的抽象概括,是不存在的;对象是类的实例化的结果,是真实存在的;
对象的引用:
person是一个引用,是指向一个可以指向Person类的对象的引用。真正创建对象的语句是右边的new Person("张三");
Person person;
person = new Person("张三");
person = new Person("李四");
//这里让person先指向了“张三”这个对象,然后又指向了“李四”这个对象。也就是说,Person person,这句话只是声明了一个Person类的引用,它可以指向任何Person类的实例。
Person person1 = new Person("张三");
Person person2 = person1;
//person1和person2都指向了“张三”这个对象。
也就是说,一个引用可以指向多个对象,而一个对象也可以被多个引用所指。
面向对象的特征:
封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节(当然也无从知道),但可以通过该对象对外的提供的接口来访问该对象。
对于封装而言,一个对象它所封装的是自己的属性和方法,所以它是不需要依赖其他对象就可以完成自己的操作。
使用封装有三大好处:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息,实现细节。
http://www.cnblogs.com/chenssy/p/3351835.html
继承定义了类如何相互关联,共享特性。
使用继承需要了解三点:
1、子类拥有父类非private的属性和方法。
2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展(如果变量同名可能会覆盖父类中的变量,可以使用super)。
3、子类可以用自己的方式实现父类的方法。
继承涉及到三点:构造器、protected关键字、向上造型
构造器:对于构造器而言,它只能够被调用,而不能被继承。对于继承,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要显示的指定父类的构造器,而且必须是在子类构造器中做的第一件事(第一行代码)
protected:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。所以对于任何继承了此类的子类而言或者其他任何位于同一个包的类而言,此类是可以访问的。
向上造型:动态绑定
我们需要明确,继承存在如下缺陷:
1、父类变,子类就必须变。
2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。
3、继承是一种强耦合关系。
总结:慎用
子类不能访问父类什么?私有属性和方法;构造方法和构造代码块;同名成员变量和静态方法(必要时,使用super关键字,否则会发生隐藏,默认访问子类中的);同名非静态方法(必要时,使用super关键字)
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
根据时期:
编译时多态:方法的重载;
运行时多态:
基于继承实现的多态
基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
1. 向上转型:父类引用指向子类对象,用子类来实例化父类;
Father f = new Son();向上转型
Son son1=(Son)f;向下转型//编译和运行都不会出错
2.向下转型:子类引用指向父类对象,父类强制
Father f1 = new Father();
Son son2 = (Son)f1;//编译没错,运行出错;子类引用不能指向父类对象
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
基于接口实现的多态
在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
根据形式:
行为多态--方法的重载和方法的重写;
对象多态--向上造型和向下造型;
多态有什么好处?
有两个好处:
1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承
2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用,
https://www.cnblogs.com/hai-ping/articles/2807750.html
https://www.cnblogs.com/chenssy/p/3372798.html
权限修饰符 返回值类型 方法名(形参列表){方法体;return 返回值}
对于基本类型的数据,传的是实际类型,被改变后,也不会被影响原来的值--值传递;
对于引用类型的数据,传的是地址值,若地址被改变后,会影响原来的对象的值---引用传递;
|
值传递(call by value) |
引用传递(call by referrence) |
描述 |
一个用于把数据或值传递给 其它函数或方法的函数或方法 |
一个用于把数据或值传递给 其它函数或方法的函数或方法 |
适用语言 |
以c为基础的编程语言 |
以c为基础的编程语言,不包括c本身 |
传递的参数 |
实参副本 |
实参地址 |
变化 |
实参副本发送变化 |
形参变化会影响实参的值,而实际参数的地址不会发生改变 |
值修改 |
实参的原值不发送改变 |
实参的原值改变 |
内存位置 |
实参和形参会被创建在不同的内存中 |
实参和形参会被创建在同块一内存中 |
安全性 |
实参安全 |
实参不安全,需要小心处理 |
默认 |
大多编程语言 |
可以被大多编程语言支持,而不是默认 |
方法的递归:循环调用本身;
子类基本类型返回值=父类基本类型返回值;
子类引用类型方法返回值<=父类引用类型返回值;
子类跑出的异常<=父类跑出的异常;
子类方法权限>=父类方法权限;
如:
如果父类的方法返回值数据类型是引用类型,子类要么和父类一致,要么是其子类,子类可以拿父类的方法或者自己的方法,但是父类不能拿子类的方法。
class A{
public void n(){}
}
class B extends A{
public void m(){}
}
class C{
Public B m(){return null;}
}
class D extends C{
Public A m(){return null;}
}
C c=new D();//向上造型
B b=c.m();//c对象是C类的声明的,就可以去访问C类中的方法,调用完方法返回值是B类,就可以去访问B类中方法
A a=c.m();//方法的具体执行看子类,去调用的是D类中的方法,调用完之后返回A类,就可以去访问A类中的方法---A类中的方法接不住B类中的方法
特点:与类同名,没有返回值;
作用:创建对象,初始化属性;
可以写return,规避不合法;
this关键字:代表对当前对象的引用
super关键字:
代表当前类的父类对象的应用;
子类构造方法中默认添加父类无参构造方法,如果父类没有无参构造必须手动指定父类有参构造方法;
super语句必须子类构造方法在首行;
static修饰的方法里不能出现this和super,因为static是类的。
非static修饰的方法里,可以出现this和super来调用属性和方法。
public class SupClass {
public static String name="bbbbbb";
public String gender;
public int age;
public SupClass() {
super();
}
public SupClass(String gender, int age) {
super();
this.gender = gender;
this.age = age;
}
public static void drink() {}
public void eat() {}
}
public class SubClass extends SupClass {
public static int a = 2;
public int b;
public String c;
public static void main(String[] args) {
SubClass sc = new SubClass("ccc");
sc.fff();
}
public SubClass() {
super();
}
public SubClass(String c) {
System.out.println(c);
}
public void fff() {// 如果是static修饰的会报错
super.drink();// 调用父类静态drink方法
super.eat();// 调用父类非静态方法
String a = super.name;// 调用父类静态属性
System.out.println(name);
System.out.println(a);
super.name = "aaaaaaaa";
System.out.println(name);
}
}
输出:
ccc
bbbbbb
bbbbbb
aaaaaaaa
局部代码块:方法中用{}包裹起来的代码,用来限定变量生命周期以及使用范围,提高栈内存使用率;
构造代码块:类中,创建对象时优于构造方法执行;
静态代码块:与类一同加载,只加载一次;
根本的加载顺序:静态(代码块、属性、方法..)>构造代码块>构造方法
权限修饰符:
public 所有类
private 仅限本类
protected 本类 子类 同包类
默认 本类同包类中
静态变量:随着类一同加载(所以不能在方法中定义),只加载一次,只分配一次内存;存放到方法区,属于共享变量;有默认值;
静态方法:随着类加载到方法区;方法区中存储,栈中执行;可以重载;可以继承,但是不可以重写,(因为如果子类出现 了和父类一模一样的静态方法,也是没有任何关系的两个方法,之后父类静态方法会被子类隐藏,如果一个父类型的变量指向子类对象,那么调用的其实还是父类的静态方法。静态方法是类在加载时就被加载到内存中的方法,在整个运行过程中保持不变,因而不能重写。但非静态方法是在对象实例化时才单独申请内存空间,为每一个实例分配独立的运行内存,因而可以重写)如果父子类中存放方法签名一致的方法,要么都是静态方法,要么都是非静态方法;非静态方法可以直接调用静态方法,静态方法不可以直接调用非静态方法,但是可以通过创建对象来:对象.方法/变量名来间接调用。
静态代码块:使用static关键字{}起来;只加载一次;父类静态代码块>子类静态代码块>父类构造代码块>父类构造方法>子类构造代码块>子类构造方法;
final+变量:对于基本类型,一旦赋值,值就不可变了;对于引用数据类型,指的是地址不变,值可以变;
final+方法:可以继承,可以重载,但是不可以重写/隐藏;
final+类:不能被继承;
final修饰参数:表示传递进去的实参不可以被修改
public class ConcreateClass {
public static void main(String[] args) {
ConcreateClass c = new ConcreateClass();
int i = 0;
c.test(i);
}
public void test(final int i){
// i++; //final参数不可改变,所以i加上1会报错
System.out.println(i);
}
public void test(final Person p){
//p = new Person(); --final参数不可变,所以给变量p赋予新的引用会报错
p.setAge(11);
}
}
特性:
没有方法体;
不能创建对象;
如果类内有抽象方法,这个类也要声明为抽象类;
抽象类中不一定包含抽象方法,因为也可以有实体方法,但是有抽象方法的类必定是抽象类。
使用: abstract+类名
注意:
子类是正常类,父类是抽象类,子类必须重写父类抽象方法 ;
子类是抽象类,父类是抽象类,子类不必重写父类抽象方法。
修饰问题:
方法不能被final/static/private修饰;私有和最终方法不能被重写,静态方法先于对象产生,没有具体对象不能重载。
不能被其他包的默认访问权限修饰符访问;
public abstract class AbstractTest {
//可以定义构造方法,但是不能实例化
AbstractTest(){}
//可以定义普通成员变量
public String name;
public int age;
//抽象方法
public abstract void eat();
//普通方法
public void drink(){
int clock;
System.out.println("喝饮料");
}
}
特性:
不能创建对象;
jdk1.8之后在全部为抽象方法的基础上,可以在抽象方法前加上default或者static把抽象方法变成实体方法;
支持类多实现接口、接口多继承接口;
没有构造方法;
接口中方法默认使用public abstract ,属性使用public static final修饰
public interface InterfaceTest {
//这是默认public abstract修饰的抽象方法
void eat();
//这是JDK1.8下的新特性---使用static或default关键字创建普通方法
static void drink() {
System.out.println("啤酒");
}
static String drink1(){
return "张三";
}
default void sleep() {
System.out.println("席梦思");
}
default String sleep1() {
return "席梦思";
}
//这是JDK1.9下的新特性---私有方法
private void init() {
System.out.println("Initializing");
}
}
在java 7及早期版本中,接口非常简单,只包含public abstract方法。
但从java 8开始,接口中允许添加public static 方法和public default方法。
java 9 则在接口允许添加private方法.
|
接口 |
抽象类 |
定义方法 |
全部为抽象方法,默认被public abstract修饰,jdk1.8中允许加上default或者static把抽象方法变成实体方法。java 9 则在接口允许添加private方法. |
和普通类一样,同样可以拥有成员变量和普通的成员方法,而且构造方法的访问方式和普通类一样; 不必须有抽象方法 |
定义变量 |
默认被public static final静态常量修饰 |
可以被不同的修饰符修饰 |
是不是类 |
不是类 |
是类 |
使用方法 |
interface 接口名 |
abstract class 类名 |
能否创建对象 |
不能 |
不能,但是有构造方法 |
与类的关系 |
类可以实现多个接口 |
单继承 |
与自身关系 |
接口可以继承接口,而且支持多继承 |
抽象类可以继承抽象类 |
说明 |
抽象类是对象的抽象 |
接口是一种行为规范 |
要求 |
实现类必须实现接口中所有的抽象方法,而不是接口中的所有方法 |
同左 |
设计原则 |
抽象类是自底向上抽象而来的 |
接口是自顶向下设计出来的 |
JDK1.8新特性https://blog.csdn.net/qq_29411737/article/details/80835658
JDK1.9新特性https://blog.csdn.net/dghafq/article/details/78131252
为什么要使用内部类?
在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
成员内部类:
类内方法外;
成员内部类中不能存在任何static的变量和方法;
成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
静态内部类:
类内方法外,随着外部类一同加载;
可以定义静态属性和方法
只能访问外部类静态属性和静态方法;
方法内部类:
只能在定义的方法内部使用;
只能定义非静态属性和方法和静态常量;
匿名内部类:
匿名内部类就是继承类或者实现接口,去重写抽象方法,只在它创建的时候使用一次;
另外,接口定义接口、接口中定义内部类类、类中定义接口要求内部的东西都是静态的;
垃圾回收机制:
针对对象:堆内存
首先对象创建的时候,先放到新生代(发生在新生代的回收成为初代回收),如果在新生代中的伊甸园区经过扫描一次依然存在,就挪的幸存区,在多次扫描后如果依然存在,则放到老生代,而老生代的扫描频率远远低于新生代,老生代的回收成为完全回收;
API:Application Programming Interfaces应用程序接口,提供接口以及接口以下的所有类。
Object:是所有类的顶级父类---是java中唯一一个没有父类的类。
clone()---返回一个内容已被拷贝在一块新堆内存中的新对象,如果要实现克隆操作就要先实现Cloneable接口。克隆对象。克隆完成之后会产生一个新的对象,这个新对象和原对象的地址不同但是属性值是一样的。
finalize()---通知系统进行垃圾回收,等同于System.gc()。
getClass()---返回实际创建的类,或者运行类。
hasCode()---返回一个对象的哈希代码值,码值在0-2^31约40亿左右,散列分布,造成数值唯一,来表示地址hascode的值跟程序、对象、运行时期都有关系。
toString()---返回对象的字符串表示形式。以后也会进行频繁重写。
equals()默认是比较地址值,可以重写自己定义:
1.判断地址值
2.参数对象是否为null
3.对象类型是否一致
4.比较属性
手写equals方法
字符串的重写equals方法会去判断字符串的值是否相等。
面试总结:==和equals有什么区别?
当比较基本类型的时候,==判断的是实际数据;对于引用类型而言==判断的是地址。
equals只能作用于引用类型,默认比较的是两个对象的地址;当重写equals的时候按照重写之后的要求进行比较。
有关String的辨析:
String s;//声明一个变量,没有分配内存
String s=null;//没有对象产生
String s="";//创建一个字符串为空的字符串对象
String s = “ ”; //有1个对象,存储在常量池中,值为空即null。
String s = new String(); //堆内存中存储一个对象,值为空。
String s = new String(“abc ”); //2个对象一个堆内存中,一个方法区中--String类型的一个构造方法String(String str)传入的参数也是一个对象,所以就是两个对象。如果字符串常量池中已经有了String a ="abc",那么就是一个对象
只有使用"文本"方式创建的String对象之间使用”+“链接产生的新对象才会被加入字符串池中。对于所有包含new方法创建的对象使用”+“都不会被加入字符串池中。
null
null是关键字,大小写敏感;
null是引用数据类型的默认值;
null既不是对象也不是一种数据类型,它仅仅是一种特殊的值,你可以将其赋予任何引用类型,也可以将null强制转化成任何类型。如
String str=(String)null;
Integer I = (Integer)null;
不能使用非静态方法来使用一个值为null的引用类型变量,将会跑出空指针异常。但是可以使用静态方法使用一个值为null的引用类型变量。因为静态方法使用静态绑定,不会跑出空指针异常
null和空不一样,null表示一个字符串对象的引用指向null,也就是说还没有指向任何的内存空间;
空表示声明一个字符串类型的引用,其值为"",这个str引用指向的是空字符串的内存空间;
Test t = null;
t.普通方法//报错
t.静态方法//没有问题
方法内的变量必须初始化,静态成员变量可以不用初始化,会有系统默认值。
还可以把null传递给方法如:
Public void print(Object obj){…}--->print(null)不会报错,只会优雅的退出。
|
接口 |
抽象类 |
定义 方法
|
全部为抽象方法,默认被public abstract修饰,jdk1.8中允许加上default或者static把抽象方法变成实体方法 |
抽象方法和普通方法; 不必须有抽象方法 |
属性 |
可以定义,默认被public static final修饰,直接定义即可 |
可以定义 |
是不是类 |
不是类 |
是类 |
使用方法 |
interface 类名 |
abstract class 类名 |
能否创建对象 |
不能 |
不能,但是有构造方法 |
与类的关系 |
类可以实现多个接口 |
单继承 |
与自身关系 |
接口可以继承接口,而且 支持多继承 |
抽象类可以继承抽象类 |
包装类:
针对基本数据类型提供了各种操作的类---包装类。
byte |
short |
char |
int |
long |
float |
double |
boolean |
void |
Byte |
Short |
Character |
Integer |
Long |
Float |
Double |
Boolean |
Void |
(自动)封箱--将基本数据类型转成对应的包装类。
int i=1;
Integer in = new Integer(i);//底层调用valueOf方法自动封箱
(自动)拆箱--将包装类转成对应的基本数据类型。
Integer in=new Integer(5);
int i=in;//底层通过对象调用int intValue()自动拆箱
需要注意以下几点:
1.不是new的Integer时候,在-128-127范围内,如果两个基本数据类型的值相等,那么这两个包装类对象地址值同样相等;反之,地址值则不相等。
不仅是Integer,Short、Byte、Long、Char都具有相应的Cache。但是Byte、Short、Long的Cache有固定范围:-128至127;Char的Cache:0至127。
https://www.jianshu.com/p/9cb9c61b0986
2.由于自动封箱的问题,所以值在-128到127之间的时候会进行判断,如果值在-128到127之间,会直接指向常量池。如果不在这个范围内,会在底层new integer(value)实际上指向了堆内存。如果包装类和对应的数据类型做操作会进行自动拆箱。
3.字符串转成不同类型的包装类,在转换的过程中都会会检测符号;一旦出现非数字符号会报出数据格式异常;
Integer in=new Integer("-123x");//NumberFormatException
Double in=new Double("2.345");
字符串转成基本类型,通过static int parseInt(String s)注意,字符没有该方法。
Boolean(String s)仅当传入字符串入不为null且不区分大小写时等于"true"才会返回true。传入其他字符串都会返回false
4.
字面值的哈希码值都是固定的,所以当传入常量值时,哈希码值就是字面值本身。
包装类对象的哈希码值都是固定的。
Boolean包装类的对象的hashCode返回值如果传入的是true,就返回1231;如果是false,就返回1327.
null的哈希码值默认是0;
Double.NaN==Double.NaN返回false;
另外关于hashcode方法
Public int hashCode()
这个方法返回对象的散列码,返回值是int类型的散列码
关于hashCode方法,一致的约定是:
重写了equals方法的对象也要重写hashCode方法。
第一:在某个运行期间,只要对象的(字段)变化不会影响equals方法的决策结果,那么,在这个期间,无论调用多少次hashCode,都必须返回同一个散列码;
第二:通过equals调用返回true的两个对象的hashCode一定一样
第三:通过equals返回false的两个对象散列码不需要不同,也就是他们的方法的返回值允许出现相同的情况。
总结:等价的对象必须产生相同的散列码。不等价的对象,不要求产生的散列码不相同。空对象的哈希码值为0
A instanceof B
A是一个对象(使用new实例的对象)
B是一个类
Father f = new Son()
f instanceof Son true f引用的实例就是一个Son实例
f instanceof Father true
f instanceof Object true
equals()公约:
自反性: x.equals(x),一定true
对null:x.equals(null),一定false
对称性:x.equals(y),则y.equals(x)
String:
字符串底层是final修饰的char类型的数组,是一个最终类,因此不能被继承。
创建之后不能改变,可以共享--底层有一个不可改变的字符数组。
所有常量都要放到常量池,字符串在常量池是地址的形式存在,其他常量存储的是真实值。
任意字符串都是String类的对象;
堆里存放字符串的值,运行池里存放的是对地址的引用,运行池里的地址指向堆里的字符串存放区,而栈里的变量则指向运行池里的存放地址的地址。
来看两道题目
ab链接之后还会在创建一个new StringBuilder对象
字符串拼接和StringBuilder拼接谁更高效?
1.空间
字符串拼接:
String S="";//存储拼接结果,1个对象
for(String i:S){
s+=i;//创建了3*100=300个对象
}
StringBuilder拼接
StringBuilder sb = new StringBuilder();//1
for(String i:str){
sb.append(i);//1*100=100
}
2.时间
字符串拼接100000个字符串花费3420ms,StringBuilder拼接1000000个字符串花费15ms---所以拼接多个字符串优先选择StringBuilder来拼接。
StringBuilder执行效率高,但是线程不安全--jdk1.5
StringBuffer执行效率低,但是线程安全--jdk1.0
String str="wduv";
System.out.println(str.replaceAll("d", "c"));wcuv
System.out.println(str);wduv
字符串类是声明为final的,替换只不过是生成了一个新的字符串,StringBuilder弥补了String的不足。
有关String的辨析:
String s;//声明一个变量,没有分配内存
String s=null;//没有对象产生
String s="";//创建一个字符串为空的字符串对象
String s = “ ”; //有1个对象,存储在常量池中,值为空即null。
String s = new String(); //堆内存中存储一个对象,值为空。
String s = new String(“abc ”); //2个对象一个堆内存中,一个方法区中--String类型的一个构造方法String(String str)传入的参数也是一个对象,所以就是两个对象。如果字符串常量池中已经有了String a ="abc",那么就是一个对象
只有使用"文本"方式创建的String对象之间使用”+“链接产生的新对象才会被加入字符串池中。对于所有包含new方法创建的对象使用”+“都不会被加入字符串池中。