这个学期学习JAVA基础课,虽说之前都自学过,但在学习时仍可以思考一些模糊不清的问题,可以更深一步的思考。在这里写下一些需要深入的知识点,对小白们也很友好~


一、Java数据类型

1、基本数据类型

这个经常在微信公众号有关面试中见到,基础中的基础,于是拿出来看看。

共有八大基本数据类型,分别是byte, short, int, long, char, float, double, boolean

整型 byte、short、int、long
字符型 char
浮点型 float、double
布尔型 boolean

简单讲解一下:

byte:

byte 数据类型是8位、有符号的,以二进制补码表示的整数;
最小值是 -128(-2^7);
最大值是 127(2^7-1);
默认值是 0;
byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
例子:byte a = 100,byte b = -50。
-----------------------------------------------------------------------------------
short: short 数据类型是 16 位、有符号的以二进制补码表示的整数
最小值是 -32768(-2^15);
最大值是 32767(2^15 - 1);
Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
默认值是 0;
例子:short s = 1000,short r = -20000。
------------------------------------------------------------------------------------
int: int 数据类型是32位、有符号的以二进制补码表示的整数;
最小值是 -2,147,483,648(-2^31);
最大值是 2,147,483,647(2^31 - 1);
一般地整型变量默认为 int 类型;
默认值是 0 ;
例子:int a = 100000, int b = -200000。
-------------------------------------------------------------------------------------
long: long 数据类型是 64 位、有符号的以二进制补码表示的整数;
最小值是 -9,223,372,036,854,775,808(-2^63);
最大值是 9,223,372,036,854,775,807(2^63 -1);
这种类型主要使用在需要比较大整数的系统上;
默认值是 0L;
例子: long a = 100000L,Long b = -200000L。
"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。
-------------------------------------------------------------------------------------
float: float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
float 在储存大型浮点数组的时候可节省内存空间;
默认值是 0.0f;
浮点数不能用来表示精确的值,如货币;
例子:float f1 = 234.5f。
--------------------------------------------------------------------------------------
double: double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
浮点数的默认类型为double类型;
double类型同样不能表示精确的值,如货币;
默认值是 0.0d;
例子:double d1 = 123.4。
---------------------------------------------------------------------------------------
boolean: boolean数据类型表示一位的信息;
只有两个取值:true 和 false;
这种类型只作为一种标志来记录 true/false 情况;
默认值是 false;
例子:boolean one = true。
---------------------------------------------------------------------------------------
char: char类型是一个单一的 16 位 Unicode 字符;
最小值是 \u0000(即为0);
最大值是 \uffff(即为65,535);
char 数据类型可以储存任何字符;
例子:char letter = 'A';。

2、引用数据类型

除了基本数据类型外的都属于引用数据类型,例如String,数组,Scanner,Random等都属于引用数据类型

所有引用类型的默认值都是null

3、自动类型转换

低-------------------------------------------------------------------------------->高

byte,short,char -> int -> long -> float ->double

转换从低级到高级,必须满足转换前的数据类型的位数要低于转换后的数据类型,还要满足以下规则:

(1)、不能对boolean类型进行类型转换。

(2)、不能把对象类型转换成不相关类的对象。

(3)、在把容量大的类型转换为容量小的类型时必须使用强制类型转换。

(4)、转换过程中可能导致溢出或损失精度,例如:

int i = 128;
byte b = (byte) i;

因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出 。

(5)、 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:

(int) 23.7 == 23;
(int)-45.98f == -45;

(6)、来个自动转换例子:

public class ZiDongLeiZhuan{
public static void main(String[] args){
char c1='a';//定义一个char类型
int i1 = c1;//char自动类型转换为int
System.out.println("char自动类型转换为int后的值等于"+i1);
char c2 = 'A';//定义一个char类型
int i2 = c2+1;//char 类型和 int 类型计算
System.out.println("char类型和int计算后的值等于"+i2);
}
}
/*
结果:char自动类型转换为int后的值等于97
char类型和int计算后的值等于66
*/

4、强制类型转换

(1)、转换的数据类型必须是兼容的。

(2)、格式:(type)value type是要强制类型转换后的数据类型

例如:

public class QiangZhiZhuanHuan{
public static void main(String[] args){
int i = 123;
byte b = (byte)i; //强制类型转换为byte
System.out.println("int强制类型转换为byte后的值等于"+b);
}
}
//结果:int强制类型转换为byte后的值等于123

二、String家族

我们就围绕String、StringBuffer、StringBuilder来说吧!

1、执行速度比较

StringBuilder > StringBuffer > String

为什么是这样子的呢?

书中有云:String为字符串常量、而其余两者为字符串变量。对于字符串常量,也就是不可变的对象,看一段代码:

String s = "abc";
s= s+1;
System.out.print(s);
//结果: abc1

问题来了,他变了!他变了!他变了!

我明明就是改变了String型的变量s,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了。由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多低。

而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象.每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,当然速度就快了。

看个例子:

String str = “This is only a” + “ simple” + “ test”;
StringBuilder sb = new StringBuilder(“This is only a”).append(“ simple”).append(“test”);

StringBuilder.append()中间过程中产生的垃圾内存大多数都是小块的内存,锁产生的垃圾就是拼接的对象以及扩容原来的空间;而当发生String的"+"操作时,前一次String的"+"操作的结果就成了内存垃圾,垃圾会越来越多,最后扩容也会产生很多垃圾 ,影响了速率。

2、StringBuffer和StringBuilder比较

StringBuilder:线程非安全的

StringBuffer:线程安全的

当我们在字符串缓冲区被多线程使用时,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。

当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,这就是速度的原因。

3、三者的总结

(1)、如果要操作少量的数据用String

(2)、单线程操作字符串缓冲区 下操作大量数据用StringBuilder

(3)、多线程操作字符串缓冲区 下操作大量数据用StringBuffer

三、自动装箱与自动拆箱

1、什么是自动装箱与拆箱

书上给了简短的两句代码

//自动装箱
Integer value = 308; //自动拆箱
int x = value;

解释一下, 装箱就是自动将基本数据类型转换为包装类;拆箱就是自动将包装类转换为基本数据类型 。

看一下基本数据类型的包装类

2、感受一下原理

自动装箱:

Integer value = 100;

Java虚拟机会自动调用Integer的valueOf方法,编译为:Integer value = Integer.valueOf(100);

自动拆箱:

Integer value = 100;
int x = value;

Java虚拟机会自动调用Integer的intValue方法, 编译为:int t=i.Integer.intValue();

3、网上看到的两个注意点

这段有幸看到大佬的博客,想深入了解可以点过来看看,感悟更深呢。

(1) 小心空指针异常

public static void main(String[] args) throws Exception
{
Object obj = getObj(null);
int i = (Integer)obj;
} public static Object getObj(Object obj)
{
return obj;
} /*
结果:Exception in thread "main" java.lang.NullPointerException
at main.Test.main(Test.java:8)
*/

这种使用场景很常见(web),我们把一个int数值放在session或者request中,取出来的时候就是一个类似上面的场景了。所以,小心自动拆箱时候的空指针异常 。

(2)小心界限

第一段代码:

public class TestMain
{
public static void main(String[] args)
{
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200; System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
/*
结果:true
false
*/

第二段代码:

public class TestMain
{
public static void main(String[] args)
{
Double d1 = 100.0;
Double d2 = 100.0;
Double d3 = 200.0;
Double d4 = 200.0; System.out.println(d1 == d2);
System.out.println(d3 == d4);
}
}
/*
结果:false
false
*/

产生这样的结果的原因是:Byte、Short、Integer、Long、Char这几个装箱类的valueOf()方法是以128位分界线做了缓存的,假如是128以下且-128以上的值是会取缓存里面的引用的,以Integer为例,其valueOf(int i)的源代码为:

public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}

而Float、Double则不会,原因也很简单,因为byte、Short、integer、long、char在某个范围内的整数个数是有限的,但是float、double这两个浮点数却不是 。

四、内部类

学习内部类的时候老师也是一讲带过,自然也很蒙圈,想可以更加深入了解一下。

首先来说说为啥要有内部类呢?如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。

不过你可能要质疑,更改一下方法的不就行了吗?的确,以此作为设计内部类的理由,实在没有说服力。

真正的原因是这样的,JAVA中的内部类和接口加在一起,可以的解决常被C++程序员抱怨JAVA中存在的一个问题——没有多继承。实际上,C++的多继承设计起来很复杂,而JAVA通过内部类加上接口,可以很好的实现多继承的效果。

内部类分为四种:成员内部类、局部内部类、匿名内部类、静态内部类

1、成员内部类

public class Outer
{
private int i; public Outer(int i)
{
this.i = i;
} public void privateInnerGetI()
{
new PrivateInner().printI();
} private class PrivateInner
{
public void printI()
{
System.out.println(i);
}
} public class PublicInner
{
private int i = 2; public void printI()
{
System.out.println(i);
}
}
} //主函数
public static void main(String[] args)
{
Outer outer = new Outer(0);
outer.privateInnerGetI();
Outer.PublicInner publicInner = outer.new PublicInner();
publicInner.printI();
} /*
结果:0
2
*/

结论:

(1)、成员内部类是依附其外部类而存在的,如果要产生一个成员内部类,必须有一个其外部类的实例

(2)、成员内部类中不可以定义静态方法

(3)、成员内部类可以声明为private的,声明为private的成员内部类对外不可见,外部不能调用私有成员内部类的public方法

(4)、成员内部类可以声明为public的,声明为public的成员内部类对外可见,外部也可以调用共有成员内部类的public方法

(5)、成员内部类可以访问其外部类的私有属性,如果成员内部类的属性和其外部类的属性重名,则以成员内部类的属性值为准

2、 局部内部类

简要定义: 局部内部类是定义在一个方法或者特定作用域里面的类

public static void main(String[] args)
{
final int i = 0;
class A
{
public void print()
{
System.out.println("i = " + i);
}
} A a = new A();
a.print();
}

注意一下局部内部类没有访问修饰符,另外局部内部类要访问外部的变量或者对象,该变量或对象的引用必须是用final修饰的

3、匿名内部类

在多线程模块中的代码中大量使用了匿名内部类

public static void main(String[] args) throws InterruptedException
{
final ThreadDomain td = new ThreadDomain();
Runnable runnable = new Runnable()
{
public void run()
{
td.testMethod();
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++)
threads[i] = new Thread(runnable);
for (int i = 0; i < 10; i++)
threads[i].start();
Thread.sleep(2000);
System.out.println("有" + td.lock.getQueueLength() "个线程正在等待!");
}

匿名内部类是唯一没有构造器的类,其使用范围很有限,一般都用于继承抽象类或实现接口(注意只能继承抽象类,不能继承普通类),匿名内部类Java自动为之起名为XXX$1.classs。另外,和局部内部类一样,td(见上代码)必须是用final修饰的。

4、静态内部类

简要定义: 用static修饰的内部类就是静态内部类

public class Outer
{
private static final int i = 1; public static class staticInner{
public void notStaticPrint()
{
System.out.println("Outer.staticInner.notStaticPrint(), i = " + i);
} public static void staticPrint()
{
System.out.println("Outer.staticInner.staticPrint()");
}
}
} public static void main(String[] args)
{
Outer.staticInner os = new Outer.staticInner();
os.notStaticPrint();
Outer.staticInner.staticPrint();
} /*
结果:
Outer.staticInner.notStaticPrint(), i = 1
Outer.staticInner.staticPrint()
*/

结论:

(1)、静态内部类中可以有静态方法,也可以有非静态方法

(2)、静态内部类只能访问其外部类的静态成员与静态方法

(3)、和普通的类一样,要访问静态内部类的静态方法,可以直接"."出来不需要一个类实例;要访问静态内部类的非静态方法,必须拿到一个静态内部类的实例对象

(4)、注意一下实例化成员内部类和实例化静态内部类这两种不同的内部类时写法上的差别

①成员内部类:外部类.内部类 XXX = 外部类.new 内部类();

②静态内部类:外部类.内部类 XXX = new 外部类.内部类();

5、运用滴好处

(1)、Java允许实现多个接口,但不允许继承多个类,使用成员内部类可以解决Java不允许继承多个类的问题。在一个类的内部写一个成员内部类,可以让这个成员内部类继承某个原有的类,这个成员内部类又可以直接访问其外部类中的所有属性与方法,就相当于多继承了。

(2)、成员内部类可以直接访问其外部类的private属性,而新起一个外部类则必须通过setter/getter访问类的private属性

(3)、有些类明明知道程序中除了某个固定地方都不会再有别的地方用这个类了,为这个只用一次的类定义一个外部类显然没必要,所以可以定义一个局部内部类或者成员内部类,写一段代码用用就好了

(4)、内部类某种程度上来说有效地对外隐藏了自己,比如我们常用的开发工具Eclipse、MyEclipse,看代码一般用的都是Packge这个导航器,Package下只有.java文件,我们是看不到定义的内部类的.java文件的


目前每周有一节课,也在不断的思考所学内容,有值得写的地方还会继续补写,为了热爱,加油吧!

我的一些JAVA基础见解的更多相关文章

  1. 学习android学习必备的java基础知识--四大内部类

    学习android必备的java基础知识--四大内部类 今天学习android课程,因为我的主专业是JAVA,但是兴趣班却有这其他专业的同学,学习android 需要具备一些java的基础知识,因此就 ...

  2. 【java基础之jdk源码】Object

    最新在整体回归下java基础薄弱环节,以下为自己整理笔记,若有理解错误,请批评指正,谢谢. java.lang.Object为java所有类的基类,所以一般的类都可用重写或直接使用Object下方法, ...

  3. Java基础面试知识点总结

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

  4. 夯实Java基础系列7:Java 代码块和执行顺序

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  5. java面试:java基础、Io、容器

    1.java基础 1.JDK 和JRE有什么区别 ​ JDK:java开发工具包,java开发运行环境.包含了JRE. ​ JRE:java运行环境,包含java虚拟机,java基础类库. 2.jav ...

  6. Java基础知识(壹)

    写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...

  7. [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)

    如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html   谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...

  8. 【JAVA面试题系列一】面试题总汇--JAVA基础部分

    JAVA基础 基础部分的顺序: 基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法 线程的语法,集合的语法,io 的语法,虚拟机方面的语法 每天几道,持续更新!! 1.一个". ...

  9. 最适合作为Java基础面试题之Singleton模式

    看似只是最简单的一种设计模式,可细细挖掘,static.synchronized.volatile关键字.内部类.对象克隆.序列化.枚举类型.反射和类加载机制等基础却又不易理解透彻的Java知识纷纷呼 ...

随机推荐

  1. 路由懒加载---Vue Router

    一.什么是懒加载? 懒加载也就是延迟加载或者按需加载,即在需要的时候进行加载. 二.为什么在Vue路由中使用懒加载? 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常 ...

  2. [初学Python]编写一个最简单判断SQL注入的检测工具

    0x01 背景 15年那会,几乎可以说是渗透最火的一年,各种教程各种文章,本人也是有幸在那几年学到了一些皮毛,中间因学业问题将其荒废至今.当初最早学的便是,and 1=1 和 and 1=2 这最简单 ...

  3. [第十篇]——Docker 容器连接之Spring Cloud直播商城 b2b2c电子商务技术总结

    Docker 容器连接 前面我们实现了通过网络端口来访问运行在 docker 容器内的服务. 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过  -P 或  -p 参数来指定端口映射. ...

  4. React项目中应用TypeScript

    一.前言 单独的使用typescript 并不会导致学习成本很高,但是绝大部分前端开发者的项目都是依赖于框架的 例如和vue.react 这些框架结合使用的时候,会有一定的门槛 使用 TypeScri ...

  5. Vue项目中应用TypeScript

    一.前言 与如何在React项目中应用TypeScript类似 在VUE项目中应用typescript,我们需要引入一个库vue-property-decorator, 其是基于vue-class-c ...

  6. 什么是 baseline 和 benchmark

    baseline 一个算法被称为 baseline 算法说明这个比目前这个算法还差的已经不能接受了,方法有革命性的创新点可以挖掘,且存在巨大提升空间和超越benchmark的潜力,只是由于发展初期导致 ...

  7. CodeForce-762B USB vs. PS/2(贪心)

    USB vs. PS/2 CodeForces - 762B 题意:有三种电脑,分别有a.b.c个,第一种只有USB接口,第二种只有PS/2接口,第三种有两种接口,有m个鼠标,告诉你价钱和接口类型,问 ...

  8. java的运行时数据区域

    最近在看<深入理解Java虚拟机>,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构: 1.程 ...

  9. 博客主题——element v2

    主题预览 主题下载 gshang.element-v2.rar

  10. java 小算法

    //鸡兔同笼 20个头 58腿 for(int a=0;a<=20;a++) { int b = 20-a; if((2*b+4*a)==58) { System.out.println(a+& ...