[Java]基础入门-Day 1
[Java]基础入门-Day1
学习使用工具
黑马2023新版Java视频教程 https://www.bilibili.com/video/BV1Fv4y1q7ZH?p=8&vd_source=03da0cdb826d78c565cd22a83928f4c2
Java程序员进阶之路 https://tobebetterjavaer.com/overview/java-can-do-what.html
基本类型和包装类 https://blog.csdn.net/xialei199023/article/details/63251295
Java中的常量池 https://cloud.tencent.com/developer/article/1450501
零、JAVA特点与介绍
-
Java的优势
1)简单性
Java 为开发者提供了简单易用的用户体验,与其他面向对象编程语言相比,Java 的设计和生态库具有巨大的优势。Java 剔除了 C++ 中很少使用、难以理解、易混淆的特别,比如说指针运算、操作符重载,内存管理等。
Java 可以做到堆栈分配、垃圾回收和自动内存管理,在一定程度上为开发者减轻了入门的难度。
2)可移植性
如果 Java 直接编译成操作系统能识的二进制码,可能一个标识在 Windows 操作系统下是1100,而 Linux 下是 1001,这样的话,在 Windows 操作系统下可以运行的程序到了 Linux 环境下就无法运行。
为了解决这个问题,Java 先编译生成字节码,再由 JVM(Java 虚拟机)来解释执行,目的就是将统一的字节码转成操作系统可以识别的二进制码,然后执行。而针对不同的操作系统,都有相应版本的 JVM,所以 Java 就实现了可移植性。
3)安全性
Java 适用于网络/分布式环境,为了达到这个目标,在安全方面投入了巨大的精力。使用 Java 可以构建防病毒、防篡改的程序。
4)并发性
Java 在多线程方面做得非常突出,只要操作系统支持,Java 中的线程就可以利用多个处理器,带来了更好的交互响应和实时行为。
-
JVM、JRE、JDK
-
JDK(Java Development Kit)是用于开发 Java 应用程序的软件环境。里面包含运行时环境(JRE)和其他 Java 开发所需的工具,比如说解释器(java)、编译器(javac)、文档生成器(javadoc)等等。
-
JRE(Java Runtime Environment)是用于运行 Java 应用程序的软件环境。也就是说,如果只想运行 Java 程序而不需要开发 Java 程序的话,只需要安装 JRE 就可以了。
-
JVM (Java Virtual Machine) ,也就是 Java 虚拟机,由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成,屏蔽了不同操作系统(macOS、Windows、Linux)的差异性,使得Java能够“一次编译,到处运行”。
-
一、数据类型
基本数据类型
- byte/8
- char/16
- short/16
- int/32
- float/32
- long/64
- double/64
- boolean/boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。
byte、char、short在运算的时候会隐式转换为int,然后再进行运算。因此下面这段代码是错误的:
public class TyprConversionTest{
public static void main(String[] args){
byte b1 = 3;
byte b2 = 4;
byte b3 = b1 + b2; //这句因为将int赋给byte,会出现编译错误
}
}
包装类
Java中每一种基本类型都会对应一个唯一的包装类,基本类型与其包装类都可以通过包装类中的静态或者成员方法进行转换。所有的包装类都是final修饰的,也就是它们都是无法被继承和重写的。
包装类 | 包装类转基本类型 | 基本类型转包装类 |
---|---|---|
Byte | Byte.valueOf(byte) | byteInstance.byteValue() |
Short | Short.valueOf(short) | shortInstance.shortValue() |
Integer | Integer.valueOf(int) | integerInstance.intValue() |
Long | Long.valueOf(long) | longInstance.longValue() |
Float | Float.valueOf(float) | floatInstance.floatValue() |
Double | Double.valueOf(double) | doubleInstance.doubleValue() |
Character | Character.valueOf(char) | charInstance.charValue() |
boolean | Boolean.valueOf(booleann) | booleanInstance.booleanValue() |
基本类型和包装类型的区别:包装类型是对象,可以为null,可用于泛型。
二、流程控制语句
- if-else
- switch
- for循环
- for each循环:for-each 循环通常用于遍历数组和集合,它的使用规则比普通的 for 循环还要简单,不需要初始变量,不需要条件,不需要下标来自增或者自减。语法:
for(元素类型 元素 : 数组或集合)
- for each循环:for-each 循环通常用于遍历数组和集合,它的使用规则比普通的 for 循环还要简单,不需要初始变量,不需要条件,不需要下标来自增或者自减。语法:
- while循环
- break
- continue:需要在 for 循环或者 (do)while 循环中立即跳转到下一个循环时,就可以使用 continue 关键字,通常用于跳过指定条件下的循环体,如果循环是嵌套的,仅跳过当前循环。
三、Java数组
数组是对象,并非基本数据类型。
一维数组
- 声明方式:
int[] anArray
或int anOtherArray[]
- 初始化方式:
int[] anArray = new int[10]
或int anOtherArray[] = new int[]{1, 2, 3, 4, 5}
- 转为List:
List<Integer> aList = Arrays.asList(anArray)
- 排序(默认升序):
Arrays.sort(anArray)
- 查找:
Arrays.binarySearch(anArray, 4)
二维数组
- 声明及初始化方式:
int[][] triangle = new int[10][10]
,int[][] oddNumbers = { {1, 3, 5, 7}, {9, 11, 13, 15} }
打印数组
-
循环打印
-
Stream流:
Arrays.stream(cmowers).forEach(System.out::println)
-
Arrays工具类:
System.out.println(Arrays.toString(cmowers))
- 二维数组的打印:
System.out.println(Arrays.deepToString(deepArray))
- 二维数组的打印:
四、Java字符串与常量池
字符串
- 创建方式:
String s = new String("二哥")
或String s = "三妹"
- 特性:被final修饰,不可变
常量池
在JVM层面为字符串提供字符串常量池,可以理解为是一个缓存区。
使用 new 关键字创建一个字符串对象时,Java 虚拟机会先在字符串常量池中查找有没有这个字符串对象,如果有,就不会在字符串常量池中创建这个对象了,直接在堆中创建一个字符串对象,然后将堆中这个的对象地址返回赋值给变量 s。
如果没有,先在字符串常量池中创建一个字符串对象,然后再在堆中创建一个字符串对象,然后将堆中这个字符串对象地址返回赋值给变量 s,等于创建了两次。
因此通常情况下采用双引号的方式来创建字符串对象,而不是通过 new 关键字的方式。此时Java 虚拟机会先在字符串常量池中查找有没有这个字符串对象,如果有,则不创建任何对象,直接将字符串常量池中这个的对象地址返回,赋给变量 s;如果没有,在字符串常量池中创建这个对象,然后将其地址返回,赋给变量 s。
intern方法
使用双引号声明的字符串对象会保存在字符串常量池中。使用 new 关键字创建的字符串对象会先从字符串常量池中找,如果没找到就创建一个,然后再在堆中创建字符串对象;如果找到了,就直接在堆中创建字符串对象。
针对没有使用双引号声明的字符串对象来说,如果想把其内容也放入字符串常量池的话,可以调用 intern()
方法来完成。
当一个字符串调用 intern()
方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals()
方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
StringBuilder
由于字符串是不可变的,所以当遇到字符串拼接(尤其是使用+
号操作符)的时候,就需要考量性能的问题,不能毫无顾虑地生产太多 String 对象,对珍贵的内存造成不必要的压力。于是 Java 就设计了一个专门用来解决此问题的 StringBuffer 类。
StringBuffer 是线程安全的,内部使用 synchronized 进行同步。执行效率会比较低,适合多线程环境。
StringBuffer
与StringBuffer相同,但没有使用synchronized,因此不是线程安全的。执行效率高,适合单线程环境。
字符串判断相等
.equals()
:比较两个对象的内容是否相等==
:比较两个对象的地址是否相等Objects.equals()
:优势在于不需要在调用之前判空.contentEquals()
:优势在于可以将字符串与任何的字符序列(StringBuffer、StringBuilder、String、CharSequence)进行比较
字符串拼接
循环体内,拼接字符串最好使用 StringBuilder 的 append()
方法,而不是 + 号操作符。循环体内如果用 + 号操作符的话,就会产生大量的 StringBuilder 对象,不仅占用了更多的内存空间,还会让 Java 虚拟机不停的进行垃圾回收,从而降低了程序的性能。
字符串分割
split()
方法:String [] parts = mystring.split(",")
- 正则表达式
五、类与对象
组合
可以把一个创建好的类作为另外一个类的成员变量来使用,利用已有的类组成成一个新的类,被称为“复用”。
继承
继承是 Java 中非常重要的一个概念,子类继承父类,也就拥有了父类中 protected 和 public 修饰的方法和字段,同时,子类还可以扩展一些自己的方法和字段,也可以重写继承过来方法。
常见的例子,就是形状可以有子类圆形、方形、三角形,它们的基础接口是相同的,比如说都有一个 draw()
的方法,子类可以继承这个方法实现自己的绘制方法。
-
访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。应该注意到,子类一定会调用父类的构造函数来完成初始化工作,一般是调用父类的默认构造函数,如果子类需要调用父类其它构造函数,那么就可以使用 super() 函数。
-
访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。
-
重写:子类实现了一个与父类在方法声明上完全相同的一个方法。为了满足里式替换原则,重写有以下三个限制:
- 子类方法的访问权限必须大于等于父类方法;
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
- 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
-
重载:存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。应该注意的是,返回值不同,其它都相同不算是重载。
多态
比如说有一个父类Shape
public class Shape {
public void draw() {
System.out.println("形状");
}
}
子类Circle
public class Circle extends Shape{
@Override
public void draw() {
System.out.println("圆形");
}
}
子类Line
public class Line extends Shape {
@Override
public void draw() {
System.out.println("线");
}
}
测试类
public class Test {
public static void main(String[] args) {
Shape shape1 = new Line();
shape1.draw();
Shape shape2 = new Circle();
shape2.draw();
}
}
运行结果:
线
圆形
在测试类中,shape1 的类型为 Shape,shape2 的类型也为 Shape,但调用 draw()
方法后,却能自动调用子类 Line 和 Circle 的 draw()
方法,这就是 Java 中的多态。
其实就是 Java 中的多态。