Java学习(入门篇->基础篇)
前提:本文按自己的学习顺序所作,内容中融合了自己的理解
第一部分:Java入门
一、必备知识
1.1 算法设计中常用的思维方法
1.枚举法:可确定取值范围时可用
2.迭代法
3.递归法
4.分治法:把复杂问题分解成小问题
1.2 面向对象程序设计
project(工程) - module(模块) - package(包) - class(类)
1.2.1 包:可以理解成文件夹,是class的前缀。
1、定义包:
在源代码的第一行使用package关键字定义包,包名通常全部小写。
2、运行带包的类:
java 包名.类名
1.2.2 类:类(class)是同一类型对象的抽象,对象是类的实例化。
类的五大成员:属性(实例变量)、方法、构造器(构造方法)、代码块、内部类
1.3 面向对象三大特性(浅)
- 封装:Java使用四种权限修饰符来类及类的内部成员,控制类或成员的可见性范围,把该暴露的暴露出来,该隐藏的隐藏起来,当他们被调用时,体现可见性的大小
private、缺省、protected、public
- 继承:
class A{//类A:父类\superclass\超类\基类
}
class B extends A{//类B:子类\派生类
//继承后子类获得父类中声明的所有属性和方法,但由于封装性,可能不能直接调用
}
- 多态:指操作名称相同,但根据接收参数的不同,实现的功能也不同。
3.1 子类对象的多态性:
//运用多态性前
Person p1 = new Person();
Man m1 = new Man();
//运用多态性后
Person p2 = new Man();//理解的口诀:编译看左边,运行看右边
3.2 使用前提:要有类的继承关系;要有方法的重写
1.4 标识符
用于命名变量,类型,数组,文件,类和方法等。由字母,下划线(_),美元符号($)和数字组成,首字符不能是数字。
关键字和布尔常量不能作为标识符。
1.5关键字
关键字主要用途有:
- 基本类型
- 创建引用对象
- 选择语句
- 循环语句
- 控制移速
- 异常处理
- 线程同步
- 类型修饰(包含访问控制)
- 类,包和接口
- 布尔量
1.6 注释
- 单行注释 //
- 多行注释 /* … */
- 文档注释 /** … /
1.7分隔符
- 注释
- 空白符:
用于分割单词,包括有:空格,制表符(’\t‘),走纸换页(’\f‘),回车(’\r’)和换行(’\n’) - 普通分割符:
圆括号‘()’,花括号‘ {} ’,方括号‘ [] ’,分号‘ ; ’,逗号‘ ,’,点‘ . ’和冒号‘ : ’。
二、了解Java
2.1 JDK、JRE、JVM
JDK:是Java程序开发工具包,包含JRE和开发人员使用的工具;
JRE:是Java程序的运行时环境,包含JVM和运行时所需要的核心类库。
JVM:是运⾏ Java 字节码的虚拟机。
查看版本:命令提示符—>java -version
补充Java的跨平台性
JVM是整个Java实现跨平台的核心,负责解释执行字节码文件,是可运行Java字节码文件的虚拟计算机。
所有平台上的JVM向编译器提供相同的接口,而编译器只需要面向虚拟机,生成虚拟机能识别的代码,然后由虚拟机来解释执行。
当使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码只面向JVM。也就是说JVM是运行Java字节码的虚拟机。
2.2 构造器(构造方法)
构造方法:
- 声明:
public Person(){ }
(没有返回值)- 用途:
2.1搭配new关键字,创建类的对象;Person p1 = new Person();
2.2创建对象时,可以给对象的相关属性赋值;- 特性:
3.1名字与类名相同。
3.2没有返回值,但不能⽤ void 声明构造函数。
3.3⽣成类的对象时⾃动执⾏,⽆需调⽤。- 注意:
1.自己没有写构造时系统生成一个无参构造器满足使用;但自己写了构造器后系统救不会提供无参构造器了
2.3 成员变量和局部变量
成员变量:
可分为实例变量(属性)和静态变量(类变量)
- 在类中方法外;
- 在堆内存;
- 随对象的创建而存在,随对象的消失而消失;
- 有默认初始值;
- 可以被 public , private , static 等修饰符所修饰
局部变量:
- 在方法定义或方法声明里;
- 在栈内存;
- 随着方法的调用而存在,随着方法的调用完毕而消失;
- 无默认初始化值,必须定义、赋值,然后才能使用;
- 不能被访问控制修饰符及 static 所修饰
2.4 Java程序运行机制:
- 编写源代码(.java文件)
- 编译(.class/字节码文件)
- 运行
2.5 Java命名规范
- 项目名通常小写;
- 包名属于标识符,规范是全部小写;
- 驼峰命名法:
分为大驼峰法和小驼峰法
大驼峰法:指每个单词的首字母都大写,常用于类名、接口名和常量名;
小驼峰法:除了第一个单词外每个单词的首字母都大写,常用于变量名和方法名。
三、数据操作
数据类型分类
3.1基本数据类型
Java有八种数据类型:6种数字类型、一种字符类型和一种布尔型
- 整型
有byte、short、int、long;(8位、16位、32位、64位)
char类型比较特殊,本质上是整数,可以作为整数进行计算,一定意义上可以看作是整型。 - 浮点型:float、double
- 字符型char(16位)
主要用于储存字符,Java的char类型是2个字节,其范围是0~65 535,可以用于储存和处理Unicode字符编码的数据。 - boolean型,默认值是false
3.2 常量与变量
常量:
有整数常量,浮点常量,布尔常量,字符常量,字符串常量和null常量。
变量
- 局部变量:构造函数、方法或程序块内声明的变量,(方法或构造器内)只在其声明范围内有效。(存在栈空间)(局部变量使用前一定要显式赋值)
局部变量包括各种形参:
1.方法形参:类的方法的形式参数。
2.构造形参:类构造函数的形式参数。- 成员变量(属性):(类内方法外)(随对象创建,存在堆空间中)
成员变量包括类变量和实例变量:
1.类变量:包括类变量和接口变量,类变量用static修饰,接口变量可以不用。创建类或接口时,变量按默认值初始化。
2.实例变量:不使用static的类变量。
符号常量:
指使用固定的修饰词 “public static final” 声明的变量,如
public static final int MIN_VALUE=20;
通常在类中定义,通过类名引用,如 Integer.MIN_VALUE
。
程序运行过程中,符号常量的值不会且不能改变。
3.3运算符
3.3.1 算术运算符
包括单目运算符和双目运算符,也有前缀和后缀之分。运算规则是先乘除后加减,括号和单目运算符优先
单目运算符
自增,自减,取正,取负
双目运算符
加减乘除,取余
3.3.2 关系运算符
3.3.3 逻辑运算符
3.3.4 位运算符
按位运算符和移位运算符。
3.3.5 赋值运算符
3.3.6 其他运算符
- 条件运算符
- 对象运算符instanceof
用来判断一个对象是否属于某个指定的类(或其子类)的实例,如果左边表达式的对象是由右边表达式的类创建的,则运算的结果为true,否则结果为false。 - 圆括号
- 方括号
3.3.7 运算符优先性
3.4类型转换
1. 自动类型转换
对表达式进行求值时,按照字节数少的类型转换为字节数多的类型的原则转换,即byte——>short 或 char——>int——>long——>float——>double 的原则转换。
2. 强制类型转换
Q:字符型变量能否与整型变量相加减?
答案是可以。
下面的代码是可以正常运行的,结果为100
这证明字符型变量可以与整型变量进行加减运算,计算时 char 类型会自动转换为 int 类型
public class Exercise{
public static void main(String arg[]) {
char ch='a';
System.out.println(ch+3);
}
}
3.5 引用数据类型
包括:类(class), 接口(interface),数组(array),(枚举类型、注解类型、字符串(String)类型)
第二部分:Java基础
一、数组和字符串
1. 认识数组
//建立数组
double[] price = {20.31,30.41,40.51};
String[] foods = new String[]{"番茄炒蛋","地三鲜","鱼香rose"};
int arr1[] = new int[3];//动态建立一维数组
int[] arr2 = {1,2,3};//静态建立一维数组,完整版:int[] arr = new int[]{1,2,3};
int[] [] arr11 = new int[2][2];//动态建立二维数组,或者int[] [] arr11 = new int[2][]
int arr22[] [] = new int[][]{{1,2,3},{4,5}};//静态建立二维数组,其中 new int[][]可省略
1.1 辨析 == 与equals
== :
如果作用于基本数据类型的变量,则直接比较其存储的值是否相等,
如果作用于引用类型的变量,则比较的是所指向的对象的地址是否相等。
equals() : 比是否是同一个对象
//例1:
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2); // false
String str3 = "abc";
String str4 = "abc";
System.out.println(str3 == str4); // true
Student student1 = new Student(23);
Student student2 = new Student(23);
System.out.println(student1.equals(student2)); // true
str3与str4相等的原因是用到了内存中的常量池,当运行到str3创建对象时,如果常量池中没有,就在常量池中创建一个对象"abc",第二次创建的时候,就直接使用,所以两次创建的对象其实是同一个对象,它们的地址值相等。
1.2 String toString(int[ ] arr) : 输出数组元素信息
//输出数组元素
System.out.println(Arrays.toString(arr1));
1.3 void fill(int[ ] arr, int val) : 将指定数值以替换形式填充到数组中(全部替换)
Arrays.fill(arr1,4);
1.4 void sort(int[ ] arr) : 使用快排实现排序
Arrays.sort(price);
数组的元素是基本数据类型,也可以是引用数据类型,当元素是引用类型中的类时,称为对象数组。
eg:String[ ],Person[ ],Student[ ],
2. 认识字符串
定义:
2.1操作字符串的类
操作字符串的类有: String 、 StringBuffer 、 StringBuilder 。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的String 对象,然后将指针指向新的 String 对象。
而 StringBuffer、StringBuilder可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是
非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,
所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
2.2 String 类的常用方法
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
二、Java特性
1.重载和重写
重写:编译期(就是当⼦类继承⾃⽗类的相同⽅法,输⼊数据⼀样,但要做出有别于⽗类的响应时,你就要覆盖⽗类⽅法)
返回值类型、⽅法名、参数列表必须相同,抛出的异常范围⼩于等于⽗类,访问修饰符范围⼤于等于⽗类。
如果⽗类⽅法访问修饰符为 private/final/static 则⼦类就不能重写该⽅法,但是被 static 修饰的⽅法能够被再次声明。
构造⽅法⽆法被重写
重载:运行期(就是同样的⼀个⽅法能够根据输⼊数据的不同,做出不同的处理)
发⽣在同⼀个类中,⽅法名必须相同,参数类型不同、个数不同、顺序不同,⽅法返回值和访问修饰符可以不同。
2.继承和多态
继承:1. ⼦类拥有⽗类对象所有的属性和⽅法(包括私有属性和私有⽅法),但是⽗类中的私有属性和⽅法⼦类是⽆法访问,只是拥有。
⼦类可以拥有⾃⼰属性和⽅法,即⼦类可以对⽗类进⾏扩展。
⼦类可以⽤⾃⼰的⽅式实现⽗类的⽅法。
多态:多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作
(多态理解:Dog继承自Animal,Cat继承自Animal,并且子类内部写有和父类同名的方法,但使用哪一个是看父类引用指向哪个子类对象,这就是多态的体现)
多态的三个条件:
- 继承
- 重写
- 父类引用指向子类对象:
父类类型 变量名=new 子类类型(); 变量名.方法名();
在 Java 中有两种形式可以实现多态:继承(多个⼦类对同⼀⽅法的重写)和接⼝(实现接⼝并覆盖接⼝中同⼀⽅法)
3.接口和抽象类
Java中接口和抽象类的定义语法分别为interface与abstract关键字。(“继承抽象类,实现接口”,至于继承接口那是说定义新接口时可以继承别的现有接口)
- 抽象类:在Java中被abstract关键字修饰的类称为抽象类,被abstract关键字修饰的方法称为抽象方法,抽象方法只有方法的声明,没有方法体。
抽象类的特点:
a、抽象类可以包含属性、方法、构造方法,但不能被实例化只能被继承,且构造方法不能用于实例化,主要用途是被子类调用;
b、包含抽象方法的一定是抽象类,但是抽象类不一定含有抽象方法;
c、抽象类中的抽象方法的修饰符只能为public或者protected,默认为public;
d、一个子类继承一个抽象类,则子类必须实现父类抽象方法,否则子类也必须定义为抽象类;
- 接口:Java中接口使用interface关键字修饰,是抽象方法的集合。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口的定义格式与定义类的格式基本上相同,将class关键字换成interface就定义了一个接口。
public interface 接口名称{
//抽象方法
public abstract void method1();
public void method2();
abstract void method3();
void method4();
//注意:在接口中的成员方法只能是抽象方法,默认是public abstract,可以不写
}
接口的特点:
a、接口可以包含属性、方法,但无构造方法;
b、接口不能实例化
c、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现,非要实现的话要加defaultdefault void open(){ //... };
d、接口支持多继承,即一个接口可以extends多个接口,间接的解决了Java中类的单继承问题;
e、一个类可以实现多个接口,但只能实现⼀个抽象类;
//警报的接口
public interface Alram {
public static final int time = 10;
public abstract void alarm();//无方法体
}
//门的抽象类:一个“门”都有的特性
public abstract class Door {
void open();
void close();
}
//警报门的类
class AlarmDoor extends Door implements Alarm {
@Override
void oepn() {
System.out.println("打开警报门");
}
@Override
void close() {
System.out.println("关闭警报门");
}
void alarm() {
//....
}
}
4.泛型
“泛型” 意味着编写的代码可以被不同类型的对象所重用。
ArrayList就是个泛型类,ArrayList作为集合可以存放各种元素,如Integer,String,自定义的各种类型等,但在我们使用的时候通过具体的规则来约束,如我们可以约束集合中只存放Integer类型的元素,如:
List<Integer> iniData = new ArrayList<>()
三、面向对象(高内聚,低耦合)
1.方法声明的格式:
//方法声明的格式:
权限修饰符 [其他修饰符] 返回值类型 方法名(形参列表) [throws 异常类型] {
//方法头
//方法体
//注:方法内不能定义方法
}
权限修饰符:public \ private \ protected \ 缺省
2.对象数组
//另有一个Student类,内含num、state、score属性;这是StudentTest类
Student[] students = new Student[10]; //建立对象数组,类似String[] strs = new String[10];
for (int i = 0; i < students.length; i++) {
students[i] = new Student();
students[i].num = i + 1;
students[i].state = (int)(Math.random() * 6 + 1 );
students[i].score = (int)(Math.random() * 101 );
}
for (int i = 0; i < students.length; i++) {
if(students[i].state == 3){
Student stu = students[i];//为了方便表示,用stu对象依次来指向students[i]
System.out.println("num:" + stu.num + "score:" + stu.score);
}
3.重载与重写(无任何关系)
重载:
why:例如print不同类型的输出,print(char)、print(int)
特点:俩同一不同:同一个类,相同的方法名;参数列表不同(个数、类型、顺序)
注:方法重载与形参名、权限修饰符、返回类型均无关
重写:
why:子类继承自父类后,获得父类所有的属性和方法,但子类想对某些不适合它的方法进行覆盖、覆写的操作
注:1. 父类被重写的方法与子类重写的方法的方法名和形参列表必须相同
2. 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符,但子类不能重写父类中声明为private权限修饰的方法,虽然不报错,但那不叫重写
4.可变个数形参的方法
格式:(参数类型 … 参数名 )
注:可变个数形参的方法在调用时,赋的实参的个数可为0到任意
public void print(int ... nums){
}
5.方法的值传递(含方法的内存分析)
Java的内存结构主要是为:虚拟机栈、堆、方法区
虚拟机栈:以栈帧为基本单位,每个栈帧入栈对应一个方法的执行,每个方法(包括main方法)都对应一个栈帧,该方法内定义的局部变量都放在该栈帧中。
堆空间:new出来的东西(数组或对象):数组、数组的元素放在堆空间中;成员变量都放在对应的堆空间中。
方法区:加载类的模板结构。
注意:name、age、gender不是main方法的局部变量,而是Person类里的成员变量(这里没展示Person类罢了)
5.1 基本数据类型
基本数据类型存的是数据,故传的也是数值
5.2 引用数据类型
- 数组类型
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = arr1;//引用类型的变量传的是地址值
arr2[0] = 10;
System.out.println(arr1[0]);//10
2. 对象类型
Object obj1 = new Object;
object1.id = 1001;
Object obj2 = obj1;//引用类型的变量传的是地址值
obj2.id = 1002;
System.out.println(obj1.id);//1002
总的来说,数组类型和对象类型都属于引用类型,引用类型传递的是地址值
6.关键字
- import:用于使用其它包下的Java类
import 包名.类名
- this:出现的情况:
- 在方法内部使用,表示调用当前方法的对象;
- 通常是形参和属性同名了,必须用this来区分他们,this修饰的是属性,没有this修饰的是形参
this可以调用的结构:成员变量、方法和构造器
基础习题
Q1:10个数中找最大值和最小值?
import java.util.Scanner;
public class Exercise{
public static void main(String []args){
int arr[]=new int[10];
Scanner sc=new Scanner(System.in);
System.out.println("请输入10个数:");
for(int i=0;i<10;i++){
arr[i]=sc.nextInt();
}
int Max=arr[0];
int Min=arr[0];
for(int i=1;i<10;i++){
if(Max<arr[i]){
Max=arr[i];
}
if(Min>arr[i]){
Min=arr[i];
}
}
System.out.println("最大值为:"+Max+" "+"最小值为:"+Min);
}
}
Q2:判断闰年?
import java.util.Scanner;
public class LeapYear {
public static void main(String []args){
Judge();
}
static void Judge(){
Scanner sc=new Scanner(System.in);
System.out.println("请输入年份:");
int i=sc.nextInt();
if((i%4==0&&i%100!=0)||i%400==0){
System.out.println(i+"年是闰年");
}else{
System.out.println(i+"年不是闰年");
}
}
}
Q3:n个数从小到大排序输出?
import java.util.Scanner;
//输入 10 个整数,将它按从小到大的顺序输出。
public class Exercise{
public static void main(String arg[]) {
System.out.print("请回车输入10个整数:");
try {
int a[] =new int[10];
for(int i=0;i<10;i++) { //循环输入10个数
@SuppressWarnings("resource")
int n = new Scanner(System.in).nextInt();
a[i] = n;
}
int temp; //选择判断交换
for (int i=0; i<9; i++) {
for (int j=i+1; j<10; j++) {
if (a[i] > a[j]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
System.out.print("数字从小到大的顺序:");
for (int i=0; i<10; i++) { // 输出排好序的值
System.out.print(a[i] + " ");
}
}
catch (Exception e) {
System.out.print("输入错误,请重新开始输入数字");
}
}
}
四、Java集合框架
1. List,Set,Map
- List (对付顺序的好帮⼿): 存储的元素是有序的、可重复的。
- Set (注重独⼀⽆⼆的性质): 存储的元素是⽆序的、不可重复的。
- Map (⽤ Key 来搜索的专家): 使⽤键值对(kye-value)存储,Key 是⽆序的、不可重复的,value 是⽆序的、可重复的,每个键最多映射到⼀个值。
一、Collection接口下的集合:
- List:
Arraylist : Object[] 数组
Vector : Object[] 数组
LinkedList : 双向链表 - Set:
HashSet (⽆序,唯⼀): 基于 HashMap 实现的,底层采⽤ HashMap 来保存元素
LinkedHashSet : LinkedHashSet 是 HashSet 的⼦类,
TreeSet (有序,唯⼀): 红⿊树(⾃平衡的排序⼆叉树)
二、Map接口下的集合:
- HashMap :
LinkedHashMap : LinkedHashMap 继承⾃ HashMap ,
Hashtable :
TreeMap : 红⿊树(⾃平衡的排序⼆叉树)
我们常⽤的 Arraylist, LinkedList , Hashmap , HashSet , TreeSet , TreeMap ,PriorityQueue 都不是线程安全的。
解决办法是使⽤线程安全的集合来代替。
如何选⽤集合?
主要根据集合的特点来选⽤,⽐如我们需要根据键值获取到元素值时就选⽤ Map 接⼝下的集合,需要排序时选择 TreeMap ,不需要排序时就选择 HashMap ,需要保证线程安全就选⽤
ConcurrentHashMap 。
当我们只需要存放元素值时,就选择实现 Collection 接⼝的集合,需要保证元素唯⼀时选择实现
Set 接⼝的集合⽐如 TreeSet 或 HashSet ,不需要就选择实现 List 接⼝的⽐如 ArrayList
或 LinkedList ,然后再根据实现这些接⼝的集合的特点来选⽤。
第三部分 Java高级
1.线程
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。它负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
Java 程序天生就是多线程程序,一个 Java 程序的运行是 main 线程和多个其他线程同时运行。
多进程:操作系统中同时运行的多个程序
多线程:在同一个进程中同时运行的多个任务 Java中的死锁
死锁
在Java中使用多线程,就会有可能导致死锁问题。死锁会让程序一直卡住,不再程序往下执行。我们只能通过中止并重启的方式来让程序重新执行。
死锁的四个必要条件
- 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用完释放。
- 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
- 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
- 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{A,B,C,···,Z}中的A正在等待一个B占用的资源;B正在等待C占用的资源,……,Z正在等待已被A占用的资源。
2.反射
定义:反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
例如:
jdbc就是典型的反射
Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类
反射的优缺点:
优点:能够运行时动态获取类的实例,提高灵活性;
缺点:相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
3.io流
io指input和output,通过IO可以完成硬盘文件的读和写。
Java 中 IO 流分为:
按照流的流向分,可以分为输入流和输出流;
按照操作单元划分,可以划分为字节流和字符流;
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。