Java基础篇上

214 阅读8分钟

开篇先放下我的Github地址:masuo777.github.io/ 欢迎访问!!!

Java基础技术

Java最核心的一直将是Java基础,不论你的框架如何,Java的基础才是建立起实用的框架的核心。

Java概述

首先,来重新过一遍自己学习Java最开始那一段快乐的时光,以及自己没来得及了解的我们所不太了解的Java,这一次让我们一起揭开Java的神秘面纱。

什么是Java?

Java是sun公司在1995年发布的编程语言和计算平台。Java作为编程语言是我们众所周知的,那么作为计算平台的Java语言你了解多少呢。

想想Java与其他语言有啥区别:Java开发是跨平台的。

计算平台是计算机系统硬件与软件的设计和开发的基础。具有一定的标准性和公开性,同时也决定了该计算机系统的硬件与软件的性能。了解即可。

Java主要分为三个版本:

J2SE:Java2 Platform Standard Edition,java平台标准版,支持在大多数环境下适用Java应用程序,为以下两位提供基础服务。

J2EE:Java2 platform Enterprise Edition,Java平台企业版,企业版,强大,完整,健壮。

J2ME:Java2 platform Micro Edition,Java平台微型版,主要为微型机器及嵌入式设备提供运行环境。

我们经常用的是SE版本,也可以用到EE,看个人需求。

Java的特点

  • 面向对象,这里来复习一下面向对象与面向过程开发的区别。

首先有的是面向过程开发,以过程为中心,解决一个问题需要哪些过程,针对过程去开发,比如1+1,首先输入第一个数字,然后输入运算符,然后输入第二个运算符,最后计算结果,然后输出结果,代表语言是C。

其次是面向对象开发,简称OOP,面向对象是以对象为中心,代表语言是C++,Java。

这两个开发方式的区别具体可以参考:www.zhihu.com/question/27…

这个作者解释的生动形象,而且非常容易理解,还提供了面试见解。

  • 无指针,不用手动管理对象的生命周期,指针一直是c语言中最难的那部分,也是最为劝退新手的部分,在Java中完全不用担心指针的问题。
  • 静态语言开发,静态语言主要有Pascal, Perl, C/C++, JAVA, C#, Scala等
  • 跨平台性,这是Java最受欢迎的原因了吧,Java的跨平台性,让他在多个操作系统中畅通无阻的执行,而实现Java跨平台的原因就是jvm,这也是Java最核心的部分。

Java开发环境

JDK

包含Java的运行环境以及开发环境。适合开发人员开发时使用。

JRE

只包括Java的运行环境,以及部分Java的基础库。适合在项目完成之后,搭建项目时使用。

接下来进入正题。

数据类型

基本类型

Java有8种基本类型,分为整形(短整型,整型,长整型),浮点型(double,float),布尔类型(boolean),字符型(byte,char)

  • byte/8位
  • char/16位
  • short/16
  • int/32
  • float/32
  • double/63
  • long/64
  • boolean/

boolean只有两个值,true/false,没有明确的大小,jvm在编译时期为了方便,将Boolean转成int类型,因为1bit没有独立地址,而int有(byte也有)。

包装类型(封装类)

每个基础类型都会对应一个封装类,基础类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。

	Integer i = 2;//装箱,将基础类封装起来,叫装箱。调用了Integer.valueOf(2)
	int j = i;//拆箱,与之对应的就是拆箱。调用了X.intValue()

缓存池

	new Integer(123)
	Integer.valueOf(123)
    //看看这两个声明类型的区别

以上两者的区别在于:

	//new Integer(123)每次都会创建一个新的对象
	//Integer.valueOf(123)会使用缓冲池中的对象,对此调用会取得同一个对象的引用

	//实例
	Integer x = new Integer(123);
	Integer y = new Integer(123);
	System.out.println(x==y);//false

	Integer i = Integer.valueOf(123);
	Integer j = Integer.valueOf(123);
	System.out.println(i==j);//true

基本类型对应的缓存池如下:

  • boolean :true/false
  • byte :all bytes
  • short/int : -128 ~127
  • char : \u0000(第0个) ~ \u007F(第127个)

字符串String

概览

String被升为final,因此String是不可继承的(包括其他封装类)。

在Java8中,String使用char数组存储数据。

public final class String
 	implements java.io.Serializable, Comparable<String>, CharSequence {
 /** The value is used for character storage. */
 	private final char value[];
}

在Java9中,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;
}

在以上源码中可以看到String的char/byte数组都被声明为了final,所以意味着数组在声明之后就是不能变得,也就是说String声明后是不可变的。

声明为final的优点:

  • 缓存hash值,

因为String的hash值经常被调用,如hash map中的key值经常是String,String的不可变性,使得hash值也不会变,因此只需一次计算。

  • String Pool的需要

如果一个String被创建过了,那么就会从String pool 中取得引用,只有String是不可变的,才能使用String pool。

  • 安全性

String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为⽹络连接参数的情况下如果 String 是可变的,那么在⽹络连接过程中,String 被改变,改变 String 的那⼀⽅以为现在连接的是其它 主机,⽽实际情况却不⼀定是

  • 线程安全

在多个线程中String值仍保持不变,使得在线程中可以安全的使用String。

String ,String buffer ,String Builder

  • 可变性

String 不可变,String buffer和String builder可变

  • 线程安全(security)

String不可变,所以是线程安全的,

String buffer是线程不安全的

String builder是线程安全的,内部使用synchronized(锁)同步

String pool

与缓存池功能类似,用来保存着所有字符串字面量,这些字面量在编译时期就确定了。不仅如此,还可以使用String的intern()方法在运行过程将字符串添加到String pool。

这里引入了一个字符串字面量的定义:字符串字面量即指声明的String类型双引号之间的常量,如“stir”中的stir。

当一个字符串调用intern()方法时,如果String pool中已经存在一个字符串和该字符串值相等(值相等要用.equals()来判断),那么就会返回String pool中字符串的引用;否则,就会在String pool中添加一个新的字符串,并返回这个字符串的引用。

使用new新建字符串是不同的两个字符串,使用intern()方法创建的对象是对同一个字符串的引用。

String s1 = new String("123");
String s2 = new String("123");
System.out.println(s1==s2);//false
String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s3==s4);//true

使用赋值的方式创建对象时,都是从String pool中引用对象,所以他们都是相等的。

String s5 = "555";
String s6 = "555";
System.out.println(s5==s6);//true

在Java7之前,String pool存放在运行时常量池中,他属于永久代,而在Java7之后,将String pool移到了堆中,这是因为永久代的空间有限,在大量使用字符串的场景下会报Out of memory的错误。

注意:

//使用new 新建字符串会新建两个字符串(前提是String pool中不存在与新建变量值相等的对象),

Java new一个对象的过程

参考:zhuanlan.zhihu.com/p/339839277 ,这是个人觉的还算能看懂的一篇。

一看到new这个关键字,我们脑海里应该是,他在Java的堆内存中开辟了一块空间。

过程过于复杂,简单来说,就是以下几个步骤,

  1. 当虚拟机收到一条new指令时,首先检查这个指令的参数能否在常量池中定位到一个类的符号引用,然后检查这个类是否被加载解析,初始化,即验证是否第一次使用这个类,如果不是第一次使用则需要先执行对应类的加载过程,

声明

String 变量名 = 变量值;双引号

String s = “string”;

charAt用法

charAt是根据下表取出字符串中对应的字符的一种方法:字符串名称.charAt(字符下标)

String s = "String";
for(int i = 0;i<=5;i++){
    System.out.println(s.charAt(i));
}

//输出:S t r i n 

在字符串后面加字符串或字符

使用‘+=’即可,string1+=string2/

String s1="aaa";
String s2="bbb";
String s3=s1+s2;
//s3="aaabbb"

foreach的使用

只能针对数组类型的变量进行遍历输出等操作:for(类型 变量名:数组名)

String []arr = {"aaadd","aaasss","aaaaaa"};
for(String s:arr){
    System.out.println(s);
}

//输出:aaadd aaasss aaaaaa