java基础知识
这个是我学习java做的一些笔记和问题,里面有大量内容是从github(主要)和csdn中抄录的,加了我自己的一些理解。下面是参考资料链接:snailclimb.gitee.io/javaguide]
- java变量类型
基本数据类型:
1、整型:int long short byte(8位2进制来表示整数,-127-128。byte详解)
2、浮点型:float,double
3、字符型:char
4、逻辑型:boolean
[1]:<>
引用数据类型:
1、类 class
2、接口 interface
3、数组
8种基本数据类型占用内存大小:
- byte/8
- short/16
- int/32
- long/64
- float/32
- double/64
- char/16
- boolean/~(会变化)
ps:
jvm在编译boolean类型时是通过转化为int类型的1和0来实现的。jvm也支持boolean数组,通过byte数组实现。所以位数不确定。 java关于不同数据类型的内存分配
- java在编写代码的时候,将类作为参数传递是这样的:
public class DataType {
void printInformation( Class c ){
}
}
注意,参数里面class类型c是大写的。(Class是类class的包装器(构造器))
- 关于整型数据怎么用二进制表示?
正数开头是0,负数开头是1.正数开头数字之后的数字就是正数的值,如对于Byte类型的1,二进制码是00000001。而负数则是开头之后的数字取反后加一的值才是所表示的值,如-1,二进制码是11111111。
- 为什么负数要取反呢?
因为不那么做而只用0、1区分正负在表示0的时候会产生混淆,10000000和00000000都是0。为了既不浪费用来表示的位数,又能唯一表示0,故而负数取反.
- 取反容易理解(因为计算机只能进行加法),为什么要加1呢?
加1偏移一位,这样用二进制表示的负数范围内就没有0了,而是从-1开始。也是为了结果正确。
- java中,变量和变量类型实际上就是对象和类。如int是一个类,int a就是实例化一个对象?
**答:**感觉变量更像是一个容器,用来装指定类型的数据。而容器本身就是一个对象。
- java中的变量类型
1、类变量:独立于方法之外的变量,用 static 修饰。
2、实例变量:独立于方法之外的变量,用 static 修饰。
3、局部变量:类的方法中的变量。
- java在声明变量的时候有开辟空间吗?
需要先搞清楚,定义和声明变量的区别。声明和定义的具体区别:所谓定义就是(编译器)创建一个对象,为这个对象分配一块内存,并给他取上一个名字,这个名字就是我们常说的变量名或对象名。所谓声明就是告诉编译器,这个名字已经匹配到一块内存上,下面的代码用到变量或者对象是在别的地方定义的。声明可以出现多次。告诉编译器,这个名字已经被预定,别的地方再也不能用它来作为变量名或者对象名。 在java中,声明和定义没有区别,但c和c++中,函数的声明和定义有区别。 所以在java中只要声明了变量(对象),就会在内存中划分空间给它,将这个空间命名为对应的变量名(对象名)。
- java修饰符
Q:修饰符有什么用?
访问控制作用。
- final有什么用?
用final修饰的类不能被继承(断子绝孙类),方法不能被重写(但可以被继承),变量不能变更值,且必须初始化。这里值不能变更分两种情况。对于基本数据类型,是数据的值不能变更。对于引用数据类型,是引用的地址值不能变更,对应地址里存储的值(内容)还是可以改变的。 Q&A:
- java不同数据类型的内存分配是怎么样的?
- java中static的含义?
- java的垃圾回收机制怎么体现?
- 浮点数的表示
java String类
- java中出现的<>什么意思?
<>是泛型
- 类、接口、方法:
- java开辟内存空间有几种方法?
答:
-
java中基本数据类型没有String,String是jre中标准java类库中预定义的类。预定义?
-
提取子串
- 字符串拼接(两种方法)
- 判断字符串是否相等(两种方法)
- 为什么判断字符串相等的时候不能用==?
答:
- StringBuffer 和 StringBuilder
- 码点、代码单元和辅助字符
- java怎么获取数据类型?
引用类型、包装类型
-
引用类型怎么理解? 对于内存中数据,c和c++通过指针操作,而java是通过引用进行操作。 java除了8种基本数据类型,其他都是引用类型。
引用类型: 包装类型(8种基本类型的对象化)、对象、类、数组(String等)、接口
-
包装类型怎么理解?
java不是一个纯面向对象语言,因为其8种基本数据类型并不具备对象的性质。为了使者8种基本数据类型能当作对象进行操作,故而有了包装类型。每一种基本数据类型都有其对应的包装类型,丰富了基本类型的数据操作。 java有自动装包和拆包的操作,如: 通过赋值"=“实现自动拆包和装包
Integer x = 2; // 装箱 调用了 Integer.valueOf(2)
int y = x; // 拆箱 调用了 X.intValue()
- java中,对象的性质是什么?为什么说基本数据类型不具有对象的性质?
给基本数据类型添加对应的包装类型,主要是为了丰富基本类型的属性和方法,增加其操作。对象具有属性和方法。
- 枚举类型
枚举类型类似于类,但其多了约束。枚举类型可以定义在类里,也可以独立于类定义在类之外。 枚举类型不能在方法里定义。idea会报enum must not be local 错误。
-
缓存池 深入理解java装箱和拆箱
-
String string是final类,和包装类型一样不能被继承。 java 8中,String内部使用char数组存储数据
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
java 9中,String类改用byte数组存储字符串,同时使用coder来标识使用了哪种编码。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final byte[] value;
/** The identifier of the encoding used to encode the bytes in {@code value}. */
private final byte coder;
}
注意,里面的数组和变量都被声明为final,保证了String的不可变性。
String
为什么String要不可变?
1、可以缓存hash值 因为String的hash值经常被使用,如String用做HashMap的key。不可变性可以使得对应的hash值不变,因此只需要进行一次计算。
2、String Pool的需要 如果一个String对象已经被创建过了,那么就会从String Pool中取得引用。只有 当String是不可变的,才可以使用String Pool。
3、安全性考虑 String经常作为参数,它的不可变性保证了参数的不可变性。例如,作为网络连接参数情况下如果String是可变的,那么在网络连接过程中,String被改变,改变String的那一方以为现在连接的是其它主机。而实际情况却不一定是。
4、线程安全 String不可变性天生具备线程安全,可以在多个线程中安全地使用。
String、StringBuffer和StringBuilder
1、可变性
- String不可变
- StringBuffer和StringBuilder可变
2、线程安全
- String不可变,因此线程安全
- StringBuilder不是线程安全的
- StringBuffer是线程安全的,内部使用synchronized进行同步。
String Pool
public class StringPool {
public static void main(String a[]) {
String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);//==比较引用类型的存储地址值
System.out.println(s1.equals(s2));//比较引用类型指向的内容值
String s3 = s1.intern();//将s1中的字符串值与String Pool中字符串的值进行比较
// 若pool中有该字符串,则返回该字符串的引用。若无,则将该字符串加入pool后返回一个该字符串的引用。
String s4 = s1.intern();
System.out.println(s3 == s4);
String s5 = "bbb";//如果是这种赋值方式,会自动将该字符串加入到String Pool中。
String s6 = "bbb";
System.out.println(s5 == s6);
}
}
字面量和符号引用
字面量是指由字母,数字等构成的字符串或者数值,它只能作为右值出现,所谓右值是指等号右边的值,如:int a=123这里的a为左值,123为右值。常量和变量都属于变量,只不过常量是赋过值后不能再改变的变量,而普通的变量可以再进行赋值操作。 例:
int a;//a变量
const int b=10;//b为常量,10为字面量
string str="hello world";//str为变量,hello world为也字面量
像String s1 = new String("aaa");//这里的"aaa"是参数
new String("abc")
这种方式会创建两个字符串对象(String Pool中还没有"abc"字符串对象)。 "abc"属于字符串字面量,在编译时期会在String Pool中创建一个字符串对象,指向这个"abc"字符串字面量 而使用new方式会在堆中创建一个字符串对象。 一下是String构造函数的源码.
public String(String original){
this.value = original.value;
this.hash = original.hash;
}
可以看到,将一个字符串对象作为另一个字符串对象的构造函数参数时,并不是复制value数组的内容,而是指向同一个value数组。
运算
参数传递
java中的参数是以值传递的形式传入方法中的,而不是引用传递。 参数传递 这个链接里面关键的一点就是关于String类型的参数传递,因为String类型的不可变性,虽然String是引用数据类型,但其参数传递看起来却像是值传递。将字符串作为参数传递进方法后,在方法里的字符串修改实际上相当于新创建一个字符串对象。java对于字符串的=修改操作都视为新建一个字符串。
public static void main(String[] args) {
String str = "AAA";
change(str);
System.out.println(str);
}
public static void change(String s) {
s = "abc";//这里是新建了一个"abc"字符串。
}
结果:AAA
为什么说java中只有值传递 因为基本数据类型是存在栈里的,没有地址值。而引用数据类型是存在堆里的。 要想实现多参数返回值,直接返回数组。
float与double
java不能隐式执行向下转型,因为这会使精度降低。在代码中1.1默认是最高精度的double类型,java无法自动将1.1转化成float类型赋值给f。 看下面代码
float f = 1.1;//这句话会报错,因为字面量1.1是double类型的,不能将double类型赋值给float类型
//正确的赋值应该是这样
float f = 1.1f;
隐式类型转换
short s1 = 1;//这句会报和float一样的错误
//但使用+=或++运算符会执行隐式类型转换
s1+=1;
s1++;
//上面两行代码等价于
s1=(short)(s1+1);
StackOverflow : Why don't Java's +=, -=, *=, /= compound assignment operators require casting?
switch
关键字
final
static
Object通用方法
equals()
hashCode()
toString()
clone()
一、面向对象和面向过程的区别
-
面向过程:
优点:面向过程的性能比面向对象高。因为类在调用的时候需要实例化,比较消耗资源。
缺点:面向过程没有面向对象易维护、易复用、易扩展。
-
面向对象
优点:面向对象易维护、易复用、易扩展。因为面向对象具有封装、继承和多态的特性。
缺点:性能较面向过程低。
关于面向对象和面向过程的理解:
拿把大象装进冰箱这件事举例。
- 用面向过程的角度去考虑这件事:首先,将冰箱门打开。然后,将大象放进冰箱。最后,把冰箱门关上。面向过程侧重步骤。
- 而用面向对象的角度去考虑这件事时,我们是将自身置于造物主的位置。 我们首先创造了一个大象类和冰箱类。大象类里有关于大象的各种属性和大象能做的事情。比如大象能走动。冰箱类也是,有自己的属性和功能。冰箱的门会关和开。然后用两个类实例化出一个具体的大象和冰箱。我们只需要告诉大象到冰箱里去,告诉冰箱让大象进来。
二、java语言的特点
1、简单易学
2、面向对象(封装、继承、多态)
3、平台无关性(通过jvm实现)
4、可靠性
5、安全性
6、支持多线程(C++没有内置的多线程机制,调用的是系统的多线程功能。而java语言自带多线程)
7、支持网络编程并且很方便(java本身就是为了简化网络编程设计的)
8、编译与解释并存
- 关于第8点的问题:编译和解释什么意思?
编译的意思就是将程序语言文件转换为计算机可执行的二进制文件,是一次性转换,然后直接执行二进制文件。而解释的意思是一个语句一个语句的转换,然后在一句句执行,转换一句,执行一句。java里的编译是将程序语言文件先转换成java字节码文件,然后jvm对字节码文件进行解释。
三、关于JVM、JDK和JRE的解释
JVM
java虚拟机(java virtual machine)是运行java字节码的虚拟机。 java之所以能在不同的平台运行,就在jvm针对不同的系统有不同的设计,实现对于相同的字节码,它们都会输出相同的结果。
-
什么是字节码?为什么要用?
字节码是扩展名为.class的文件里的代码。它不面向任何特定的处理器,只面向虚拟机。采取字节码的原因:1、解决传统解释型语言执行效率低的问题(?)又保留了解释型语言可移植的特点。
2、字节码不针对特定机器,java程序不用重新编译就可以在不同的操作系统上运行。
java程序从源代码到运行有两次转换:
java文件(源代码)->字节码(.class文件,JVM能理解)->二进制文件(机器码)
第一次转化是JDK中的javac(编译器)编译的,第二次转化是jvm由解释的。
在.class->机器码这个过程中,JVM类加载器首先加载字节码,然后通过解释器逐行解释执行,这种方式的执行速度会相对较慢。而且,有些方法和代码块是经常被调用的(热点代码),所以后面引进了JIT编译器,JIT属于运行时编译。当JIT编译器完成第一次编译后,其会将字节码对应的机器码保存下来供下次使用。所以说jAVA是编译和解释并存。
JDK和JRE
JRE是java运行时环境(Java Runtime Environment)。 它是运行已编译的java程序的所有内容的集合。也就是说负责字节码文件的运行。包含JVM、java类库、java命令和其他基础构件。但它只是运行程序,不能创建。
JDK是java开发工具包(Java Development Kit) 它包含了JRE的一切,外加编译器(javac)和工具(javadoc和jdb)。它能创建和编译程序.
总结: JVM、JRE、JDK是后者包含前者的关系,JRE包含了JVM,而JDK包含了JRE。后者除前者外,有其他部分。
五、java和C++的区别?
相同点:
1、都是面向对象语言,都支持封装、继承和多态
不同点:
2、java不提供指针来直接访问内存,程序内存更加安全
3、java类是单继承的,C++支持多重继承。但java接口是可以多继承的。
4、java有自动内存管理机制,不需要程序员手动释放。
5、在C语言中,字符串或字符数组最后都会有一个额外的字符‘/0’来表示结束。但是,java语言中没有结束符一说。
Q:java和C语言结束符的区别反映了什么?为什么会这样?
因为java中的一切都是对象,字符串或字符数组自然也是对象,需要具体的长度。既然长度有了,自然不需要一个结束符去标识字符串或字符数组的结尾。这也造成了java中字符串的不可变性。而C语言中,字符串或字符数组长度不一定就确定,所以需要一个结束符来标识结尾。
六、什么是java程序的主类?应用程序和小程序的主类有何不同?
一个程序中可以有很多类。但只有一个类是主类。在java程序中,这个主类是指包含main()方法的类。而在java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类必须是public类。主类是java程序执行的入口点。
七、java应用程序与小程序之间有哪些差别?
应用程序是从主线程启动(main()方法)。applet小程序没有main()方法,主要是嵌在浏览器页面上运行(调用init()或run()来启动)。嵌入浏览器这点和flash小游戏类似。
八、字符型常量和字符串常量的区别?
形式上: 字符常量是单引号括起来的单个字符,字符串常量是双引号括起来的多个字符。
含义上: 字符常量实际上是一个整型值(16位的ASCII值),可以参加表达式运算;字符串常量代表一个地址值(该字符串在内存中的位置)
占用内存大小: 字符常量占两个字节(注意是两字节,而不是一字节);字符串常量占若干字节。
九、构造器Constructor是否可被override?
Constructor不能被override(重写),但是可以被overload(重载),所以可以看到一个类中有许多构造函数的情况。
十、重载和重写的区别?
-
重载
发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。 如,可以如下构造一个空的StringBuilder对象:
StringBuilder messages = new StringBuilder();也可以指定一个初始字符串:
StringBuilder todoList = new StringBuilder("To do:\n");可以看到StringBuilder()和StringBuilder("To do:\n")这两个构造方法名字是一样的,但一个参数是空,另一个参数是字符串。这种有相同的名字、不同的参数便会发生重载。
编译器会根据各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配挑选出相应方法。如果找不到匹配的参数,就会产生编译时错误。这个过程被成为重载解析。
java允许重载任何方法,不只是构造器方法。所以,要完整描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。例如,String类有4个称为indexOf的公有方法,它们的签名是:
indexOf(int) indexOf(int,int) indexOf(String) indexOf(String,int)注意: 返回值类型不是方法签名的一部分。也就是说,不能有两个名字相同、参数类型也相同但返回值类型不同的方法。
-
重写
重写是子类对父类允许访问的方法的实现过程进行重新编写,发生在子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出异常范围小于等于父类,访问修饰符范围大于等于父类。另外,如果父类方法访问修饰符为private则子类就不能重写该方法。简而言之,方法看着还是那个方法,其实内部已经发生翻天覆地的变化了。