1、Java 就业方向
JavaEE 工程师:电商、团购、众筹、sns、教育、金融、搜索
大数据软件工程师,大数据应用工程师、大数据算法工程师、大数据分析和挖掘
Android软件工程师
2、Java 应用领域
企业级应用:各类网站,金融、电信、 交通、电子商务及各大购物平台
移动端领域应用:消费与嵌入式,车载音乐设备,电视盒子、pos机、扫码等。
安卓平台应用。
3、JavaSE
3.1 什么是程序?
计算机执行某些操作或解决某些问题,从而编写的有序指令的集合
/**
* 作者: Juran on 2022-02-19 16:58
* 作者博客:iit.la
*/
public class Test {
public static void main(String[] args){
int num = 1+1;
System.out.println(num);
}
}
3.2 Java 诞生(历史)--JAVA之父
1990 sun公司 启动 绿色计划
1902 创建oak(橡树)语言 - > java
1994 gosing 参加硅谷大会,演示Java 功能,震惊世界。
1995 sum公司 正式发布 Java第一个版本
2009年,甲骨文公司宣布收购Sun
2011年,发布Java7
其余版本:
3.3 Java 技术体系平台
Java SE(Java Standard Edition) 标准版:
支持面向桌面级应用的Java平台,提供完整的Java核心Api,该版本前称J2SE
Java EE(Java Enterprise Edition)企业版:
主要针对于Web应用程序开发。该版本前称J2EE
Java ME(Java Micro Edition)移动版:
Java程序移动端上的平台,针对移动端进行支持,该版本前称J2ME。
3.4 Java 特点
简单性:
安全性:
面向对象(oop)
健壮的:强类型机制、 异常处理、垃圾的自动收集等是Java程序健壮性的重要保证。
跨平台(Java中所编译好的.class文件,可在多个系统下运行,这种特性称之为跨平台。)
语言是解释性的。
解释性语言(javasrcipt/php/java):编译后代码不能被机器直接执行,需要解释器来执行。
编译性语言(c/c++):编译后的代码,可以直接被机器执行.
3.5 Java 开发工具
sublime / idea / notepad++ / eclipse
3.6 Java 运行机制及运行过程
i. 将Java程序进行编译会生成对应的编译文件。
ii. 通过不同系统中的JVM进行编译文件的解释。
iii. 这才是实现Java程序跨平台性的重中之重。
3.6.1 什么是JVM
1.虚拟的计算机,具有指令集并使用不同存储区域,负责执行指令,管理数据、内存、寄存器、包含在JDK中。
2.对于不同平台,有不同的虚拟机。
3.屏蔽底层运行平台的差别。
3.7 什么是JDK、JRE?
JDK:
1.全称 Java Developed kit(Java开发工具)。
2.jdk = jre + java的开发工具
3.jdk是给Java开发人员使用的,其中就包含了Java开发工具,也包括了 Jre。所以安装了jdk,就不需要安装jre了。
JRE:
1.全称Java Runtime Environment Java运行环境。
2. jre = jvm + java 的核心类库。
3.包括Java虚拟机和java程序所需的核心类库等,如果需要运行一个开发好的Java程序,计算机只需要安装JRE即可。
JDK、jre、jvm的包含关系:
1.jdk = jre + 开发工具集
2.jre = jvm + java se标准库。
3.jdk = jvm + java开发工具集 + java se 标准类库。
4.运行编译好的程序,那么我们只需要jre即可。
3.8 环境搭建
省略……
3.9 第一个Java程序
编写源程序HelloWorld.java
/**
* 作者: Juran on 2022-02-19 22:12
* 作者博客:iit.la
*/
//public class HelloWorld 表示Hello是一个类,是一个public的类
//hello{}表示一个类的开始和结束
//public static void main(String[] args){ } 表示一个程序的主方法,即表示主程序入口。
//System.out.println("Hello,world"); 表示将Hello,world 输出打印在屏幕之中。
// ; 表示语句结束。
public class HelloWorld {
public static void main(String[] args){
System.out.println("Hello,world");
}
}
通过Jdk 开发工具Javac将源文件编译成字节码文件 .class,最后使用Java开发工具运行我们编写的HelloWorld程序。
3.9.1 注释
用于解释程序的文字,提高代码的可读性。是一个程序员编程的良好习惯。
a) 单行注释:
基本格式
//这是单行注释
b) 多行注释:
基本格式
/*
多行注释
/*
c) 使用细节:被注释的文字,不会被Jvm解释执行。多行注释里不允许有多行注释嵌套。
d) 文档注释:
使用Jdk提供的工具Javadoc所解析,生成一套以网页文件形式体现的该程序的说明文档。
在cmd中执行该命令,生成文档javadoc -d ./temp(保存文件路径) -xx -yy xxxx.java(源程序)
4.0 变量
变量指向内存中存在的一块空间(不同的变量,类型不同,占用空间大小不同)。
4.1 为什么需要变量?
变量是程序的基本组成单位。
不论使用哪种高级程序语言编写的程序,变量都是该程序的基本组成单位。
//示例
package com.bj287.dome;
public class HelloWorld {
public static void main(String[] args){
int a = 1; //定义一个int类型 标识符为a 值为1 的变量
int b = 2; //定义一个int类型 标识符为a 值为1 的变量
b = 12; //将12赋值给b
System.out.println(a); //打印输出a变量
System.out.println(b); //打印输入b变量
System.out.println("Hello,World");
}
}
e) 定义变量时注意点:
i. 变量必须先声明,后使用,有顺序
ii. 同一个作用域中变量名不能重名。
iii. 变量的三要数(类型 变量名 值)。
f) 程序中+号的使用
package com.bj287.dome;
public class HelloWorld {
public static void main(String[] args){
/**
* 程序中+的使用。
* 1.当+左右两边为数值类型时,为加法运算。
* 2.当+左右两边一边为字符串时,则为拼接。
*/
System.out.println("Juran" + 12);
System.out.println(12 + 12);
System.out.println(12 + 12 + "Juran");
/**
* 最终输出结果:
* Juran12
* 24
* 24Juran
*/
}
}
4.2 数据类型(重点)
不同的数据类型,存储不同类型的信息
类型 | 占用空间 | 范围 | |
---|---|---|---|
byte[1]字节 | 1 | -2^7 ~ 2^7-1 | -128~127 |
short[2]短整型 | 2 | -2^15 ~ 2^15-1 | -32768~ -32768 |
int[4]整型 | 4 | -2^31 ~ 2^31-1 | -2,147,483,648--2,147,483,647 |
long[8]长整型 | 8 | -2^63 ~ 2^63-1 | -9,223,372,036,854,775,808-9,223,372,036,854,775,807 |
4.2.1 整型细节(重点)
1.各整数类型有固定的字段范围和长度,不受os的影响
2.java的整型常量默认为int型,声明long型常量时须后加”l“ 或 ”L“
package com.bj287.dome;
public class J287_day03{
public static void main(String[] args){
//java 整型常量 默认为 int型,长度 4个字节。
int n1 = 1;
//int型在内存空间中为32bit,但long型有64bit,内存空间中仅支持范围广容纳范围小的变量,而范围小的变量不能容纳大范围。
// int n1 =1l; //错误
System.out.println(n1);
}
}
3.声明int型时,除非不足以表示大数,才使用long。
4.bit时计算机中最小的存储单位,byte是计算机中基本存储单位。
4.2.2 浮点型细节(重点)
1.构成:浮点数 = 符号位 + 指数位 + 尾数位
2.尾数部分可能会丢失,造成精度缺失(小数都是近似值。)
3.java浮点数常量默认为double类型,声明float类型,需要在常量后加上 ‘f’ 或 ‘F’
4.通常情况下double 类型(保留十位) 的精度比float (保留7位)精度高,更加精确。
package com.bj287.self_taught;
public class First_Dome {
public static void main(String[] args) {
/**
* 浮点型常量默认类型为double,声明float型常量时,需后加 'f' 或 'F'
*
*/
// folat n1 = 12.0; //默认类型为double,所以赋值给float类型,会有一个类型错误提示
float n2 = 13.0f;
double n3 = 13.0;
double n4 = 13.0f;
// 十进制数表示方式 0.25 0.25f .25(必须要有小数点。)
double n5 = .25;
System.out.println(n5);
/**
* 浮点型 陷阱,浮点数之间的比较。
*
* 在进行浮点型计算过程中会产生一个近似值的。从而导致判断失败。 所以在对小数进行相等判断时,需要注意。 正确的做法是通过Math.abs
* 将两个数相减的结果转换绝对值,让其小于一个范围之类达到近似相等。
*
* 如果对变量进行直接赋值或者通过直接查询得到的值,是可以判断相等的。
*/
double n6 = 2.7;
double n7 = 8.1 / 3;
System.out.println(n6);
System.out.println(n7);
if (n6 == n7) {
System.out.println("相等");
} else {
System.out.println("不相等");
}
// 正确写法
if (Math.abs(n6 - n7) < 0.00001) {
System.out.println("相等");
} else {
System.out.println("不相等");
}
}
}
4.2.3 字符类型(char 重点)
1.字符常量需要用' '包裹。
2.利用转移字符 “” 将字符变成特殊格式的字符型常量。
3.char 本质上是一个整数,在输出时,是Ascii码对应的字符。
4.可以将Ascii码进行强制类型转换,进行计算。
/**
* 字符类型学习
*/
public static void study_char(){
char c1 = 'a';
char c2 = '\t';
char c3 = '刘';
char c4 = 65; //输出Ascll码 对应字符
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
}
char 本质
字符是如何存储到计算机当中的?
将字符对应的码值找出,再进行存储。
存储:'a' ——>码值97——>二进制——>存储
读取:'二进制'——>码值——>'a'——>显示
字符和码之间的关系通过字符编码表决定(字符编码表事先规定好的。)
知识拓展:
AscII: 一个字节表示,一个128个字符。
Unicode:固定大小编码,一个字符表示两个字节,字母和汉字统一占用两个字节。
utf-8:大小可变的编码,字母使用一个字节,汉字使用三个字节。
gbk:可表示汉字,范围广,字母使用一个字节,汉字使用两个字节。
gb2312:可表示汉字,gb2312 < gbk
4.2.4 布尔类型
1.仅允许取值true 或 false
2.boolean 类型 占用1个字节。
3.boolean类型适合用于逻辑判断,一般用于流程控制。
4.2.5 基本数据类型的转换(convert)
1.java程序程序中进行赋值或运算时,精度小的类型可以自动转换成精度高的数据类型。
2.(byte,short) 和 char 之间不能够进行转换。
3.byte,short,char 进行运算时,将精度直接提升为int类型。
4.bollean 不参与类型转换
5.自动提升原则:表达式结果的类型自动提升为操作数中最大的类型。
6.强制转换可能会造成精度丢失,数据溢出。
/*
* 类型自动转换
*/
public static void type_convert(){
/**
* 细节一:多种类型混合运算时,
* 系统首先自动将数据类型转换成容量最大得数据类型,然后再进行计算
*
*/
int n1 = 10;
float n2 = 10 + 1.1f;
System.out.println(n2);
/**
* 反之将精度大的数据类型赋值给精度小的数据类型,就会报错。
*/
//int n4 = 12.1; //错误示例 将数据double 类型转换为 int类型。
/**
* 规则:(byte,short) 和 char 之间不能够进行类型转换。
* 一个具体的值赋值给byte时, 先判断值是否存在byte类型范围之内,如果是即可以赋值成功。
*/
byte n3 = 10;
/*
* 错误示例
* n4为整型其精度已经超过byte,再赋值与byte,即为错误做法。
*/
//int n4 = 20;
//n3 = n4;
//char c1 = n3; //错误示例,byte不能赋值与char。
/*
* byte short char 进行运算直接将精度提升int
*
*/
byte b1 = 20;
byte b2 = 30;
//byte b3 = b1 + b2; //错误。 原因:byte、short、char 进行计算直接将精度提升为int类型。所以最终不能赋值给byte类型的值
short s1= 10;
char c2 = 56;
}
4.2.6 基本类型和String类型的转换
1.基本类型转 String类型(将基本数据类型 + " "即可 )
2.将字符串变成字符而不是数字时,编译并不会提示报错,但是在运行是会抛出数字格式异常。
public static void string_parse(){
//String 字符串,引用数据类型
String s1 = "123";
//使用基本数据类型包装类的对应方法,将String转换成对应类型。
int num1 = Integer.parseInt(s1);
long num2 = Long.parseLong(s1);
float num3 = Float.parseFloat(s1);
double num4 = Double.parseDouble(s1);
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
System.out.println(num4);
//如何将字符串 转换成字符,将字符串第一个字符得到。
System.out.println(s1.charAt(0));
}
4.1 运算符(未学完)
1.运算符是一种特殊的符号,用以表示数据的运算,赋值和比较等。
4.1.1 算数运算符(arithmeticOperator)
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | +7 | 7 |
- | 负号 | b=11,-b | -11 |
+ | 加 | 8+8 | 16 |
- | 减 | 8-8 | 0 |
* | 乘 | 8*8 | 64 |
/ | 除 | 8/8 | 1 |
% | 取余 | 11%9 | 2 |
++ ++ | 自增:先自增,再运算 自增:先运算,再自增 | a=2,b=++a; a=2,b=a++; | b=3; b=2; |
-- -- | 自减:先自减,再运算 自减:先运算,再字减 | a=2,b=--a; a=2,b=a--; | b=1; b=2; |
+ | 字符串拼接 | "hellow"+"world" | helloworld |
- % 取模计算公式:a - a / b * b
注意计算时会因为类型产生的精度问题。
/* 算术运算符 */ public static void arithmeticOperator(){ System.out.println( 10 / 4); //因为整数默认类型为int,所以在计算时会将 带有的小数点出去,因此结果从2.5 变成了2 System.out.println( 10.0 / 4); //通过将表达式类型中数提升精度,改变计算结果。 double d = 10 / 4; //正常计算结果应该是2.5,但是因为是int类型整数进行计算,会舍去小数点后尾数,在进行精度提升所以最终结果还是2.0 不会是 2.5 System.out.println(d); /** * 取模 * a -a / b * b */ System.out.println( 10 % 8); System.out.println( 10 % 2); System.out.println( 10 % -2); /** * 自增自减 */ int c = 5; int e = 4; System.out.println("先自增再输出:"); System.out.println(++c); System.out.println("先输出再自增:"); System.out.println(c++); System.out.println(c); System.out.println("先自减再输出:"); System.out.println(--e); System.out.println("先输出再自减:"); System.out.println(e--); System.out.println(e); }
4.1.2 关系运算符
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
== | 相等 | 8 == 7 | false |
!= | 不相等 | 8 != 7 | true |
< | 小于 | 8 < 7 | false |
> | 大于 | 8 > 7 | true |
<= | 小于等于 | 8 <= 7 | false |
>= | 大于等于 | 8 >= 7 | true |
instanceof | 检查是否是类的 “对象” | "test" instanceof String | true |
4.1.3 逻辑运算符(72p)
a | b | a&b | a&&b | a\ | b | a\ | \ | b | !a | a^b |
---|---|---|---|---|---|---|---|---|---|---|
true | true | true | true | false | true | false | false | |||
true | false | false | false | false | true | false | true | |||
false | true | false | false | false | true | true | true | |||
false | false | false | false | true | false | true | false |
4.2 进制转换
4.3 控制结构
程序中,程序控制决定着程序是如何执行的。下面是三大流程控制结构
4.3.1 顺序结构
程序从上而下逐行执行,中间没有判断和跳转。
g) 注意:
i. java中定义变量时,采用合法的向前应用。
//正确书写
public class Test{
int num1 = 12;
int num2 = num1 + 1;
System.out.print(num2);
}
//错误写法
public class Test{
int num2 = num1 + 1;
int num1 = 12;
System.out.print(num2);
}
ii. 嗯
4.3.2 分支控制(if else)
4.3.2.1 单分支
基本语法
if(表达式){
执行代码块;(可以有多个语句。)
}
说明:当表达式为true时,才会执行代码块中的代码,如果为false,就不会执行。(当执行代码块只有一条语句时,可以不用加上{}.)
示例:
/**
* 通过sacnner类,进行信息输入
* 然后进行判断
*/
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
if(num > 1)
System.out.println("你输入的值大于1了");
流程控制图
4.3.2.2 双分支
基本语法
if(表达式){
执行代码块1;(可以有多个语句。)
}else{
执行代码块2;(可以有多个语句。)
}
说明:当条件表达式成立时,即执行代码块1,否则执行代码块2.
示例:
/**
* 通过sacnner类,进行信息输入
* 然后进行判断
*/
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
if(num == 20){
System.out.println("你输入的值等于20");
}else{
System.out.println("你输入的值不等于20");
}
流程控制图
4.3.2.3 多分支
基本语法
if(表达式1){
执行代码块1;(可以有多个语句。)
}else if(表达式2){
执行代码块2;(可以有多个语句。)
}
……
else{
执行代码块n;
}
说明:
当表达式1成立 执行代码块1,不成立执行条件表达式2,
如果表达式2成立那么执行代码块2,否则执行条件表达式n,
以此类推,如果所有表达式都不成立,那么执行else的代码块,
注意只能有一个执行入口。
示例:
/**
* 多分支 if(){
*
* }esle if{
*
* } …… esle{ } 使用
*/
// 判断一个数是否在这个1-10,10-20,20-30范围之内。
public static void dfz() {
Scanner num = new Scanner(System.in);
int uInput = num.nextInt();
if (uInput >= 1 && uInput < 10) {
System.out.println("在1-10范围之内:" + uInput);
} else if (uInput >= 10 && uInput < 20) {
System.out.println("在10-20范围之内:" + uInput);
} else if (uInput >= 20 && uInput < 30) {
System.out.println("在20-30范围之内:" + uInput);
} else {
System.out.println("该数已经超出规定范围之内:" + uInput);
}
}
流程控制图
4.3.2.4 嵌套分支
一个分支中嵌套另一个完整的分支结构,里边的分支称为内分支,外部分支称为外分支,规不要查过三层。(可读性不好)
基本语法:
if(){
if (){
if-else……
}else{
if-else……
}
}
示例
/**
* 根据淡旺季的月份和年龄,打印票价。
/public static void qtfz() {/
* 输入月份 年龄 判断票价
*/
Scanner iMonth = new Scanner(System.in);
int month = iMonth.nextInt();
Scanner iAge = new Scanner(System.in);
int age = iMonth.nextInt();
if (month >= 4 && month <= 10) {
if (age < 18) {
System.out.println("半价");
} else if (age >= 18 && age <= 60) {
System.out.println("60");
} else if (age > 60) {
System.out.println("1/3");
} else {
System.out.println("输入错误");
}
} else {
if (age >= 18 && age <= 60) {
System.out.println("40");
} else {
System.out.println("20");
}
}
4.3.3 switch 分支结构
基本语法
switch(表达式){
case 常量1
语句块1;
break;
case 常量2
语句块2;
break;
case 常量n
语句块n;
break;
default
default语句块;
break;
}
iv. switch 关键字,表示switch 分支
v. 表达式 对应一个值
vi. case 常量1,当表达式值等于常量值1时,就执行语句1代码块。
vii. break;表示退出switch。
viii. 如果case常量1,表达式值不等于常量1时,就往后推直到找到case 常量n 与 表达式 相等时。
ix. 如果表达式 没有一个case 常量n相等,则执行default 的代码块。
流程控制图:
注意点:
1.表达式数据类型要与case后的常量类型一致。
2.switch(表达式) 中 表达式的返回值必须是(byte,short,int,char,enum,String);
3.case 常量n 中的常量n 必须是常量而不能是变量。
4.break用于跳出switch语句块,如果没有加上break。则会将switch语句块执行完。
示例:
/给定学生的考试成绩,根据考试成绩判断学生的考试等级,其中考试成绩为小数[90,100] A[80,90)B[70,80) c[60,70)D[0,60)E/
int score= 40;
switch ((int) score / 10) {
case 6:
System.out.println("e");
break;
case 7:
System.out.println("d");
break;
case 8:
System.out.println("c");
break;
case 9:
System.out.println("b");
break;
case 10:
System.out.println("a");
break;
default:
System.out.println("输入错误");
;
}
4.3.4 如何确立分支类型的选择
x. 如果判断的具体数值不多,而且符合类型(byte,short,int,char,enmu,String)这6种类型,虽然两个语句都可以使用,建议使用switch语句。
xi. 对于区间的判断,对结果Boolean类型的判断,使用if、if的使用范围更广。
4.3.5 循环
for 循环:将你的代码进行重复的执行。
基本语法
for(变量初始化;循环条件;循环变量迭代){
循环体(执行的代码);
}
- for关键字,表示循环控制
- for有四要素,(1).循环变量初始化。(2)循环条件。(3)循环操作。(4)循环变量迭代
- 循环操作:可以有多条语句,也就是循环执行的代码。
- 如果循环只有一条语句,可以省略{},建议不要省略。
流程控制图。
示例:
注意事项与细节说明:
1.循环条件返会的是一个布尔值。
2.for(;循环条件;)中的初始化变量和循环迭代变量是可以写到其他地方,但是两边的;号不能省略。
- for(循环初始化变量;循环条件;循环迭代变量)循环初始化变量及循环迭代变量可以有多个,但需要用逗号"," 隔开。
while循环
基本语法
循环变量初始化
while(循环条件){
循环体;(语句)
循环变量迭代;
}
说明:
1.while循环也有四个元素
2.只有四个元素放的位置不一样。
流程控制语句
注意事项与细节说明:
循环条件返回一个布尔值
进入循环体之前先进行判断。
do……while 循环
基本语法:
循环变量初始化;
do{
循环体;(语句);
循环变量迭代;
}while(循环条件);
说明:
1.do while 是关键字。
2.也有循环四要素,只有位置不一样。
3.先执行,后判断,也就是说,一定会执行一次。
4.最后有一个;分号。
5.while 和 do……while 区别:一个先执行
流程控制
注意事项与细节说明:
循环条件返回一个布尔值
do……while循环先执行,再判断,所以至少要执行一次。
4.4 数组
1.引用数据类型
2.是一种简单的线性数据结构。
2.是一个长度固定的容器,存储统一类型的数据。
3.必须先进行数组的变量声明,才可以进行使用。
为什么需要数组?
我们定义变量时如果我们需要多个值那么我们就需要多个变量,创建多个变量同时不仅显得代码臃肿可读性较差还会大大占据内存空间,所以在建立多个同类型数据时我们就可以用到数数组。
如何使用数组?
1.动态初始化
如果不知到数据具体的值就可以使用该种方法进行数据动态存储
数组的定义一、
数组存储数据类型[] 数据变量名 = new 数组存储数据类型[数组长度]
int[] a = new int[]
意为创建一个数组,名字为a,数据类型为int
例
int[] a = new int[3];
Scanner scanner = new Scanner(System.in);
//a.length 表示数组长度
for (int i = 0; i < a.length; i++) {
System.out.println("请输入第" + i + "个值");
a[i] = scanner.nextInt();
}
System.out.println("打印输出输出值");
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
数组的定义二、
1.先声明数组
数据类型 数组名[];
数据类型[] 数组名;
2.创建数组
数组名 = new 数据类型大小[大小]
a = new int[10];
3.注意点:
声明数组后并不会分配内存空间,socres会是null。进行创建数据对象后才会分配内存空间。
如果在进行声明数组后没有创建数组会造成空指针异常。NullException
2.静态初始化
已知数组的元素个数,使用该种方法进行数据的存储。
1、基本语法
数据类型[] 数组名={元素值1,元素值2,……};
数据类型数组名[]={元素值1,元素值2,……};
1.注意
上面方式等价于:数据类型[] 数组名 = new 数据类型[数组长度];
使用数组注意点:
1.数组是多个相同类型的组合,实现对这些数据的统一管理。
2.数据中的元素可以是多种数据类型,但是不能混用。
3.创建数组后,拥有默认值,byte 0,short 0,int 0,long 0,float 0.0,double 0.0,char u0000,boolean false,String null.
4.使用数组步骤:声明数组并开辟空间,给数组各个元素赋值,使用数组。
5.数组下标从零开始。
6.数组下标必须在声明数组的范围内使用,否则会报:数组下标越界异常:ArrayIndexOutOfBoundsException
7.数组属于引用数据类型,数组型数据是对象。
8.声明数组后需要创建空间。不然会出现控制指针异常.NullException
4.5 面向对象
编程世界也是一个世界。
4.5.1 什么是 类?
类是将物体的特性抽取出来,将这些抽象出来的特性存放在在一个自定义的数据类之中也就是我们所说”类“。
4.5.2 什么是对象?
我们将类进行实例化,再对其进行特性的具体化也就是我们所说的对象。
4.5.3 快速理解类和对象之间的关系
示例:
public class OOP {
public static void main(String[] args) {
/**
* 实例化(创建对象)
* 理解为:我们想拥有一个猫咪时,我们就对其进行实例化,让我们的猫猫拥有行为或一些特性。
*/
Cat cat = new Cat();
cat.name = "GG";
cat.age = 6;
cat.play();
/**
* 实例化2创建对象)
*/
Cat cat1 = new Cat();
cat.name = "MM";
cat.age = 8;
cat.play();
}
}
class Cat{
/**
* 将猫的特征抽象为属性、行为(方法)。
*/
String name;
int age;
void play(){
System.out.println("猫咪" + this.name + "在爬沙发");
}
}
从以上示例来说:说明类和对象之间是有密切的关系的,类 是 对象 的一些特性抽取出来放在公共的数据类型之中,然后进行实例化(创建对象),让对象拥有不同的特性及行为。
对象的jvm内存分配机制
方法区:存放代码,方法调用在栈分配空间。
方法在主方法区进行加载,栈执行完方法后,马上出出栈。(压栈弹栈)
1.栈:一般放置数据类型。
2.堆:存放对象(数组)、数据。
3.方法区:常量池、类加载信息(只会加载一次)
4.5.4 成员方法。
什么是成员方法?
类是对象的一个模板,我们需要创建一个对象时,但是我们这些对象又不能只有属性,他需要拥有一些行为。就比如我们人,我们不是只拥有姓名、年龄、身高以及样貌、我们还拥有除特定属性的一些特征,比如我们会跳舞、游泳、跑步、打游戏,这对我们来说是一种行为,对于对象这个概念中来说这是一种方法同时也是一种行为。
为什么需要用到成员方法?及方法的妙处
1.我们创建创建一个数组
int[] arr = {1,2,3,4,5,6,7,8,9,10};
2.我们就将数组进行进行遍历
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);s
}
从上面两个步骤中我们可以看到遍历一个数组是非常简单的,但是如果我们定义三个 、五个、十个……呢。编写for循环的次数就是N次。但是我们使用方法即可一次性解决这些问题.
public static void outPrintArray(int[] arr){
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
}
3.最后创建多个数组。
int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
int[] arr2 = {1,2,3,4,5,6,7,8,9,10};
int[] arr3 = {1,2,3,4,5,6,7,8,9,10};
//只需要调用方法即可完成数组遍历
outPrintArray(arr1);
outPrintArray(arr2);
outPrintArray(arr3);
方法不仅能使代码复用性高同时使代码可读性提高,代码告别臃肿。
成员方法基本结构
public 返回数据类型 方法名(参数列表){
//方法体
语句;
retunr 返回值;
}
使用细节:
1.访问修饰符(private protected 默认 private)
2.返回类型:
- 一个方法最多只有一个返回值。
- 返回值可以是任何类型。
- 如果方法要求要有返回数据类型,在最后方法返回的返回值要与方法定义的返回类型一致。
- 方法返回类型为void 时,可以没有return语句,或者 可以写 return;
- 定义方法名时最好见名之意
3.参数列表:
- 一个方法可以有0个参数和多个参数,多个参数时需要用逗号","隔开
- 参数类型没有限制且可以有多个。
- 一个参数名对应一个数据,传入或使用数据时要对应数据类型和参数名。
4.方法调用。
- 同一个类中直接 书写 方法名() 即可进行调用
- 跨类进行调用时 书写 类型.方法名字() 进行调用
- 同时调用方法与修饰符息息相关。
重点---递归(215-227)
4.5.5 重载
一个类中,多个同名的方法存在,但是参数列表不一致。
重载的好处:
减轻了起名的麻烦,减轻记名字的麻烦。
重载的理解
一个方法可以重复进行书写,类型及方法名可以一致但是参数列表不能个数及类型不能一致。
方法重载的细节:
方法名:必须相同。
参数列表:必须不同(参数类型或个数或顺序,至少有一样不一样。参数名没有要求)
返回类型没有要求。
4.5.6 可变参数
将多个同名何同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数的实现。
基本语法
访问修饰符 返回类型 方法名(参数类型... 形参名){
}
public static void add(int... nums) {
int sum = 0;
for (int i : nums
) {
sum += i;
}
System.out.println(sum);
}
注意事项:
int... 表示接受的参数是可变参数,类型是int,即可以接受多个int(0-多)
使用可变参数,可以当作数据来进行使用,即 可当作数据
参数
可变参数的实参可以是0个或者多个。
可变参数的实参可以为数组
可变参数的本质就是数组(那么也就是说可以直接将对应类型的数组当作实参放入参数列表。)
可变参数可以与普通参数放置在一起,但是需要确保可变参数是放普通参数的最后。
一个形参列表中只能出现一个可变参数
4.5.7 作用域
变量分类
局部变量(方法内):
一般指在成员方法中定义的变量
成员变量(整类体):
一般指方法中定义的变量。
注意点:
全局变量具有初始值而局部变量需要进行初始化过后才能进行使用,因为没有默认值。作用域不一致。
属性名和局部变量可以进行重名,访问时遵循就近原则。
同一个成员方法中不能局部变量不能重名。
属性声明周期较长,他随着类的创建而创建,伴随对象的销毁而销毁,而局部变量随着随着代码块的执行而创建,随着代码块的销毁而进行销毁。即在一次调用的方法之中。
不同点:
作用域不同
全局变量:可以被本类进行使用,或其他类使用对象的调用);
局部变量:只能在本类中对应的方法中使用。
修饰符不同。
全局变量/属性可以加修饰符.
局部变量不能够加修饰符。
4.5.8 构造方法/构造器
创建一个对象是,如果我们需要在创建对象的同时就将这个对象的一些特性进行定义,那么就可以使用构造器。
那么构造器的作用是什么?构造器的主要作用是对新对象进行初始化。
基本语法
[修饰符] 方法名(参数列表){
方法体;
}
特点:
构造器的修饰符可以默认
构造器没有返回值。
方法名和类名必须一致
参数列表与成员方法一样的规则。
构造器在对象创建时调用。
构造起默认存在且没有参数,如果一定定义构造器那么将会将默认构造器进行覆盖。
如果没有定义构造器,系统在编译阶段会自动生成一个默认的无参构造器。
4.6.1 封装
封装就是将抽象出来的数据,和对数据操作的方法封装在一起,数据被保护在程序内部。程序的其他部分只有通过授权的操作才能对数据进行操作。
封装的好处:
保证数据的安全性。
隐藏使用细节,方法<---调用。
封装的好处:
对属性进行私有化。
提供一个set方法对属性进行赋值。
提供一个get方法获取属性的值
封装可以在构造器的基础上进行使用。
4.6.2 继承
为什么 需要继承?
将同一种事物抽象为类时,会发现类中会有很多的属性和方法相同,所以我们可以在这些类中抽出父类,将这些类中相同的属性和方法定义在父类中,同时也解决了代码重用性降低的问题。即 类是对象的模板,对象是类的一个个体。
扩展性及维护行进行提高。
基本语法
class 子类 extends 父类{
1.private:
2.public:
3.protected:
4.default
}
1.子类会自动拥有父类定义的属性和方法
2.父类又叫超类,基类
3.子类又叫派生类。
子类继承父类注意事项:
1.子类虽然继承了父类的共有属性和共有方法,非私有的属性能够进行访问,但是私有属性不能在子类中直接进行访问,需要通过公共方法进行访问。同时子类也不能继承父类的构造方法。
2.子类会默认调用父类的构造器,完成父类的初始化。(虽然在子类中看不到子类调用父类的构造方法,但是在编译是就将父类构造方法进行了调用。)
通过
3.子类创建对象时,不管使用的是哪个构造器,默认情况下都会去调用父类的无参构造器,
如果父类没有提供无参构造器,但是提供了有参构造器,有参构造器存在的同时会覆盖掉无参构造器,那么子类必须要通过super(参数列表)的方式指定父类中的有参构造器。
4.如果希望去指定父类中的的某个构造器,调用方法为 : super(参数列表)。
5.super 在使用时,必须放在构造参数的第一行(只能在构造器中使用)。
6.super()-表示父类中的构造器 和 this()- 当前子类中的构造器。都只能放在构造器的第一行,因此两个方法不能共存在一个构造器。
7.Java中所有类都是Object 类的子类,Object是所有类的基类。
8.父类构造器的调用不限于直接父类!将一直追溯直到Object类。
9.单继承,不允许有多继承
10.不能滥用继承,子类和父类之间必须满足 is-a的逻辑关系。
Super关键字:
super表示父类的引用,用于访问父类的属性、方法、构造器。
使用细节:
- super虽然能访问父类的属性,但是不能访问父类的private属性。
- 同理访问父类方法时,不能访问private方法。
- 当子类与父类中的成员(成员/属性)重名时,子类可以通过super来调用父类中的属性或方法。
- super的访问不限于直接父类,如果直接父类还有父类与当前直接父类和本类中有同名成员时,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则去访问。
super和this的比较
区别点 | this | super |
---|---|---|
访问属性 | 找本类中的属性,如果没有则从父类中找 | 直接访问父类中的属性 |
调用方法 | 找本类中的方法,如果没有则从父类中找 | 直接访问父类中的方法 |
调用构造器 | 调用本类构造器,需要放到首行。 | 调用父类构造器,必须放在子类构造器首行。 |
特殊 | 表示当前对象 | 子类中访问父类对象 |
访问修饰符总结
访问修饰符 本类 同包 不同包子类 其他
private √
默认的(friendly) √ √
protected √ √ √
public √ √ √ √
4.6.3 重写
子类拥有一个父类同名、同类型、同返回参数的方法,那么就可以说子类的这个方法覆盖(重写)了父类的方法。
注意事项及需要满足的条件:
子类的方法的参数、方法名,要和父类方法的参数,方法名称完全一致。
子类方法的返回类型和父类一样,或者是父类返回类型的子类。
例如
父类类型是Object ,子类方法的返回类型是String
子类方法返回类型String 的 是继承自Object。
子方法不能缩小父方法的访问权限。
重载和重写
4.6.4多态
方法和对象具有多种形态,是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
多态的体现
- 重写和重载中的多态主要体现在方法之中。
- 对象多态(核心,重点,难点。)
(1). 一个对象的编译类型和运行类型可以不一致。
(2). 编译类型在定义对象时,就确定了,不能改变。
(3).运行时是可以进行改变的。
(4).编译类型看定义 = 号的左边,运行类型看 = 号右边。
例
Animal animal = new Animail();
Animal animal = new Cat();
adimal编译类型是Animal运行类型是Cat
animal = new Dog();
animal 的运行类型变成了Dog,编译类型依然还是Animal
多态注意事项和细节:
多态的前提:两个对象存在继承关系。
多态的向上转型:
(1).本质:父类的引用指向了子类的对象。
(2).语法:父类类型 引用名 = new 子类类型();
(3).特点:编译类型在左边,运行类型在右边。
(4).不能调用子类中的方法。
可以调用父类中的所有成员(但是要遵循修饰符权限规则。)。
不能调用子类中特有成员(在编译阶段,能调用到哪些成员方法,是由于编译类型决定的。);
最终的运行效果还是要看运行类型,即调用方法按照从本类进行方法的查找,然后调用。
多态的向下转型(个人李姐:编译类型与运行类型不一致时才需要向下转型):
(1)子类类型 引用名 = (子类类型) 父类引用;
(2)只能强转父类类型的引用,不能强转父类的对象。
(3)要求父类的引用必须指向当前目标类型的对象。
(4)可以调用子类类型中的所有成员。
4.6.5 Object 类
Object 类是所有类得根类。
==比较符:
- 可以做基本数据类型的判断也可以做引用数据类型的判断。
- 如果判断基本类型则判断值是否相等
- 如果判断引用类型则判断地址是否相等,即判定是不是同一个对象。
equals方法
- 是Objects中的方法,只能判断引用类型。
- 默认判断的是地址是否相等,子类中往往重写该类方法,用于判断内容是否相等。
HashCode
- 提高具有哈希结构的容器,
- 有两个引用,如果指向的 是同一个对象,则哈希值肯定是一样的。
- 两个引用,如果指向的是不同的对象,则哈希值不一样。
- 哈希值主要是根据地址号来写的!不能完全将哈希值等价于地址
这里推出一个知识点。先看看Objet 中 toString方法。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
类名.包名 @ 符连接 最后加上十六进制的HashCode
}
我们在进行对象toString的时候,由于没有进行Object对象的方法toString的重写,所有类会继承父类的toString方法。我们对对象进行输出打印时会出现这样一串字符
com.bj287.dome.Student@154617c
这是因为对象没有对继承的方法进行重写,所以会输出这样一串字符,具体实现结果就是Object类中toString写法
同时我们将该对象的hasdcode码进行打印输出,最后会得到这样一个结果。
22307196
我后我们使用计算器 将 这串编码转换成十六进制,看到
22307196 转换成 154 617C
这和Object中的toString方法输出的字符串一致。
同时也有说到,hashCode是根据地址来写的,生成的一串数字并不等同于地址。
Finalize方法(垃圾回收)
当对象被回收时,系统自动调用该对象的Finalize 方法。
什么时候被回收呢?当对象没有任何引用时,则jvm就认为这是一个垃圾对象,就会使用垃圾回收装置销毁该对象。销毁前就会调用finalize方法。
垃圾回收机制由系统决定,同时也可以使用Sytem.gc 对垃圾进行回收。
4.5.6 小项目(零钱通)
4.5.7 类变量和类方法
类方法
类变量也叫静态变量/静态属性,是该类所有对象的公共享有的属性,任何一个对象都可以对该属性进行访问,取到的都是同一个值,修改时也修改的时也修改的是同一个变量。
如何定义类变量:
访问修饰符 static 修饰符 数据类型 变量名;
static 访问修饰符 数据类型 变量名;
如何访问静态变量:
类名.变量名[推荐]。
对象名.变量名。
类方法
类方法也叫静态方法。基本机构
访问修饰符 static 返回类型 方法名(参数列表){ };
static 访问修饰符 返回类型 方法名(参数列表){ }
类方法的调用。
类名.类方法。
对象名.类方法。
注意事项:
- 什么时候用这个变量:当所有对象需要用到共享的变量时。
- 类和实例变量的区别:类是所有对象公共享有的,而实例变量只能通过对象是每个对象享有的。
- 加上static则称为静态变量。
- 类方法(静态方法)中不允许使用和对象有关的关键字,比如this和super,普通方法(成员方法)可以。
- 类方法(静态方法)中只能访问静态变量活静态方法。
- 普通成员,既可以访问静态方法,非静态的方法,可以访问静态成员和非静态成员。(遵守访问修饰符权限规则。)静态方法只能访问静态成员
4.5.8 理解main方法语法
语法格式:public static void main(String[] args){}
- main方法时虚拟机调用。
- java虚拟机需要调用类的的main方法,所以该方法的权限修饰符必须是public
- java虚拟机执行时不必要创建对象,所以main方法时必须是static
- 该方法接收String类型的数组参数,数组中保存了执行java命令时传递给运行类的参数。
java 执行的程序 参数1 参数2 参数3 参数4
注意:
- main方法可以访问本类中的静态方法/属性。
- 但不能访问该类中的非静态成员,必须创建一个对象的实例过后才能通过这个对象去访问类中的非静态成员。
4.5.9 代码块
代码块又称初始化块,数据类成中的成员,类似方法将语句封装在方法体中,通过{}包围起来。
但是和方法又不同,没有方法名没有返回值,没有参数,只有方法体,不是通过类对象或类显示调用,而是类进行加载时,或创建对象时隐式调用。
基本语法
[修饰符]{
};
说明:
- 修饰符:两种状态可选,不选或者用static进行修饰
- 代码块分为两类,使用static修饰的称为静态代码块,没有static修饰的,叫普通代码块。
- 逻辑语句可以为任何逻辑语句。
- 号可以写上
注意事项:
- static代码块也叫做静态代码块,作用是对类进行初始化,而且随着类的加载而执行,并且只会执行一次。
- 普通代码块,每实例化一个对象都会执行
- 类什么时候被加载?
创建对象实例化时。
创建子类对象实例时。
使用类的静态成员时(静态属性/静态方法)
- 普通的代码块:创建实例时会被隐式调用,被创建一次,就会调用一次。如果使用的是类的静态成员时,代码块并不会执行。
- 创建一个对象,在一个类调用顺序:
静态代码块和静态属性初始化,都会随着类的加载而执行,而且只会执行一次,在存在多个静态类和静态属性的变量初始化,则按照他们的顺序调用。
- 普通代码块和普通属性的初始化:
普通代码块和普通属性的初始化,他们优先级一致,所以,则按照他们的顺序调用。
- 构造器执行顺序排在最后。
- 构造器隐喻默认调用super和普通代码块。
- 所有类默认继承Object类。
- 执行优先级 父类静态代码块——>子类静态代码块——>父类普通代码块——>父类构造方法——>子类普通代码块——>子类构造方法。
4.6.0 单例设计模式
静态方法和属性的经典使用。
设计模式是通过大量实践中总结和理论化之后优选出来的代码结构。
什么是单例模式?
采用一定的方法保证整个系统中,一个类的实例对象只能存在一个对象实例,并且该类只提供一个取得对其对象实例的方法。
单例模式两种方法:
饿汉式:
懒汉式:
4.6.1 Final 关键字
- 当不希望类被继承时,可以使用final关键字修饰
- 不希望某个方法被重写与重载时,可以使用final关键字进行修饰。
- 不希某个成员属性被修改时,可以使用final关键字进行修饰。
- 不希望某个局部变量被修改时,可以使用final关键字进行修饰。
- 不希望某个实例化对象地址被修改时,可以使用final关键字进行修饰。
使用Final关键字注意事项。
- Final 关键字修饰的属性一般称作为常量,必须进行初始化。
- 如果Final修饰属性是静态的,则初始化的位置只能是(定义时 在静态代码块,构造器中赋值,在代码块中。)
- 方法虽然不能被重写,但是可以被继承。
- Final不能修饰构造方法
- final和static往往搭配使用,效率更高,底层编译器做了优化处理。
- 包装类(Integer,Double,Float,Boolean等都是Final),String也是Final类。
4.6.2抽象类
为什么要使用抽象类?
列举:一个动物的类中,有某些方法,但是又不确定这些方法是如何实现的,可以将整个方法定义为抽象方法,那么这个类也就是抽象类。
简介:
- abstract关键字修饰一个类时,这个类就叫抽象类。
- 用abstract关键字来修饰一个方法时,这个方法就叫抽象方法。(修饰符 abstract 返回类型 方法名(参数列表);没有方法体)
- 抽象类的价值更多会在于设计模式之中。
细节:
- 抽象类不能被实例化
- 抽象类不一定包含抽象方法,但是有抽象方法的类必须声明为abstract。
- abstract 只修饰方法和类,不修饰属性和其他。
- 抽象类可以有任何成员。非抽象方法、构造器、静态属性等等。
- 抽象方法没有主体。
- 如果继承一个抽象类,则必须实现抽象类的所有方法,或者自身也声明为abstract
- 抽象方法不能使用private、final 和 static 来修饰,因为这些关键字违背了重写的规则。
4.6.3 接口
接口就是给出一些没有实现的方法,封装到一起,某个类需要使用时就可以实现这个接口,并将具体的方法写出来。
基本语法:
interface 接口名{
//属性
//方法(抽象方法,默认实现方法,静态方法-jdk8以后)
}
实现接口
class 类名 implements 接口名{
//自己的属性
//自己的方法
//必须实现接口的抽象方法。接口中抽象方法可以省略abstract关键字
}
- jdk7.0 以前接口中的所有方法都没有方法体。
- jdk8 以后可以有静态方法,默认方法(default),也就是说接口中可以有方法的具体实现。
接口使用注意事项:
(1)接口不能被实例化。
(2)接口中所有方法被public 修饰,接口抽象方法可以不用abstract修饰。
(3)一个普通类实现接口,就必须将该接口的所有方法实现。
(4)抽象类实现接口,可以不用实现接口的方法。
(5)一个类可以实现多个接口。
(6)接口中的属性,只能是final,而且是public static final修饰符。其属性必须进行初始化。
(7)接口属性的访问形式:接口名.属性名。
(8)一个接口不能继承其他类,但是可以继承多个别的接口。
(9)接口修饰符 只能是public 和默认,这和类的修饰符一样。
(10)JDK9 可以使用private
例子:
interface A{
int a = 66; //等价于public static final int a = 66
}
class B implements A{
}
B b = new B();
System.out.println(A.a); //66
System.out.println(b.a); //66
System.out.println(B.a); /66
接口多态性:
4.6.4 接口 VS 继承
接口是用来干嘛的?实现方法的?广义的理解就是实现他的方法并且重写它的方法,但兴许那么我们心许可以换一种方式去理解,有一个猴子它的只能只有爬树
,那么它想拥有鸟儿的能力飞翔
那他需要怎么做呢?
这时候可以理解成猴子通过接口拥有了它这一个技能,那为什么不是继承呢?继承也可以实现啊?继承同时也是可以实现的,但是他们只是同属于动物一个大类,猴子属于灵长类动物,但鸟是鸟类动物,他们就不是同一个物种。
还有你要明确一点继承不能多继承,但是实现是可以进行多实现的,所以我们要让猴子拥有飞翔这个技能那么我们就可以通过接口让它拥有这一个功能。
线程
反射
……其余重新写文章,太多了。