Java语言跨平台原理
跨平台
Java程序可以在任意操作系统上运行
跨平台原理
在需要运行Java应用程序的操作系统上,安装一个与操作系统对应的Java虚拟机(JVM Java Virtual Machine)即可.
JRE和JDK
JRE(Java Runtime Environment)
JRE是Java程序的运行环境,包含JVM和运行时所需要的核心类库
我们要运行一个已有的Java程序,那么只需要JRE即可
JDK(Java Development Kit)
是Java程序开发工具包,包含JRE和开发人员使用的工具.
其中的开发工具:编译工具(javac.exe)和运行工具(java.exe).
JDK,JRE和JVM的关系
JDK包含了JRE和开发工具
JRE包含了JVM和核心类库
常用的DOS命令
操作 | 说明 |
---|---|
盘符名称 | 盘符切换,D:回车,表示切换到D盘 |
dir | 查看当前路径下的内容 |
cd 目录 | 进入单级目录,cd develop |
cd … | 回退到上一级目录 |
cd 目录1\目录2… | 进入多级目录,cd develop\workspace |
cd \ | 回退到盘符目录 |
cls | 清屏 |
exit | 退出命令提示符窗口 |
HelloWorld案例
public class HelloWorld{
public static void main(String[] args){
System.out.println("HelloWorld");
}
}
编译java程序: javac HelloWorld.java
运行java程序: java HelloWorld
注释
注释是在程序指定位置添加的说明信息,注释不参与编译与运行
注释分类
1.单行注释
格式://注释信息
2.多行注释
格式:/*注释信息*/
3.文档注释
格式:/**注释信息*/
例:
/*
类的定义格式:
public class 类名{
}
这是我定义的HelloWorld类
*/
public class HelloWorld{
/*
这是main方法
main方法是程序的入口方法,代码的执行是从main方法开始的
*/
public static void main(String[] args){
// 这是输出语句,输出内容是HelloWorld,输出内容可以改变
System.out.println("HelloWorld");
}
}
关键字概述
关键字是被java语言赋予了特定含义的单词
- 关键字的字母全部小写
- 常用的代码编辑器,针对关键字有特殊的颜色
常量
在程序运行过程中,其值不可以发生改变的量
常量分类:
字符串常量:用双引号括起来的内容
整数常量:不带小数的数字
小数常量:带小数的数字
字符常量:用单引号括起来的内容,只能存放单个字符
布尔常量:布尔值,表示真假,true或者false
空常量:一个特殊的值,空值,null(空常量是不能直接输出的)
数据类型
基本数据类型
整数数据类型:byte,short,int,long
浮点型:float,double
字符型:char ,双引号括起来,只能保存单个字符
布尔型:boolean(默认值false)
引用数据类型
键盘输入对象
//1.导包,类的前面加载
import java.util.Scanner
//2.创建键盘输入对象
Scanner sc=new Scanner(System.in);
//3.用户输入数据
int num=sc.nextInt();
//4.将输入的数据打印在控制台
System.out.println(num);
标识符的命名规则
由$ , _ , 数字,字母组成,不能由数字开头,不能使用java定义的关键字,不宜过长
类型转换
隐式转换
小转大,可以直接赋值
特殊关注:byte,short,char运算时,不管是否有更高的数据类型,都会自动提升为int,再进行运算
强制转换
强制转换有可能造成精度损失,不建议使用
目标数据类型 变量名=(目标数据类型)变量值;
int a=130;
byte b=(byte)a;
运算符
算数运算符
+,-,* :
/,%
switch语句
语句格式
switch(表达式){
case 值1 :
语句体1;
break;
case 值2:
语句体2;
break;
......
defalult:
语句体n+1;
break;
}
注意:在switch语句中,如果case控制的语句体后面不写break,将会出现穿透现象
现象:当开始case穿透,后续的case就不会匹配效果,内部的语句都会执行,直到看见 break,或者将整体switch语句执行完毕,才会结束
循环语句
for循环语句
for循环格式:
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
执行流程:
1.执行初始化语句
2.执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
3.执行循环体语句
4.执行条件控制语句
5.回到2继续
while循环语句
格式:
初始化语句;
while(条件判断语句){
循环体语句;
条件控制语句
}
执行流程:
1.执行初始化语句
2.执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
3.执行循环体语句
4.执行条件控制语句
5.回到2继续
数组
定义一个数组
数据类型[] 数组名; int[] arr={};
数据类型 数组名[]; int arr[]={};
数组的动态初始化,初始化时只指定数组的长度,由系统分配初始值
数据类型[] 数组名=new 数据类型[数组长度]
例:申请一个长度为5的数组
int[] arr=new int[5];
只明确元素个数,不明确具体数值
数组的静态初始化,初始化时就可以指定数组要存储的元素,系统还会自动计算出该数组的长度
格式: 数据类型[] 变量名=new 数据类型[]{数据1,数据2,…}
明确元素个数与具体数值
java一个数组的内存分配
java大致分为栈内存,堆内存,方法区
方法区中有class字节码文件与main方法,在程序运行时main方法加载进栈内存,定义变量也在栈内存进行,每new一次会在堆内存中申请一块内存空间
方法
方法概述
一段具有特定功能的代码块就是方法
方法与方法之间是平级的关系,不能嵌套定义
方法的定义格式与调用:
1.无参方法的定义格式:
public void 方法名(){
方法体
}
方法的调用格式://直接调用,一般用来调用没有返回值的方法
方法名();
2.带参方法的定义格式
public void 方法名(数据类型 形参变量名,...){
方法体
}
方法的调用格式://直接调用,一般用来调用没有返回值的方法
方法名(实参变量的值);
形参:方法定义时的参数,作用是接收实参
实参:调用方法时传递的真实数据
3.带返回值的方法定义
public 返回值的数据类型 方法名(数据类型 形参变量名){
方法体
return 返回值;
}
方法的调用格式: //赋值调用
跟返回值相同的数据类型 变量名=方法名(实参值);
System.out.println(变量名);
//打印调用:必须调用有返回值的方法
System.out.println(getSum(实参值));
return: 返回返回值,结束方法
进制的转换
在java中,数值默认都是10进制,不需要加任何修饰
二进制:在java中以0b开头,b大小写都可以
八进制:数值前面以0开头
十六进制:数值前面以0x开头,x大小写都可以
书写时,虽然加入了进制的标识,但打印在控制台的都是10进制数据
这些的规定都是从jdk8开始的
任意进制到十进制的转换
公式:系数*基数的权次幂相加
系数:每一位上的数
基数:几进制就是几
权:从数值的右侧,以0开始,逐个+1增加
十进制到任意进制的转换
公式:除基取余
使用源数据,不断的除以基数(几进制,基数就是几)得到余数,直到商为0,再讲余数倒着拼起来即可
原码反码补码
计算机中的数据都是以2进制补码的形式在运算,而补码则是通过反码和原码推算出来的
原码(可直观看出数据大小)
就是二进制定点表示法,最高位为符号位,0为正,1为负,其余表示数值大小
反码
正数的反码与其原码相同;负数的反码是对其原码按位取反,但符号位不变
补码
正数的补码与其原码相同;负数的补码是在其原码的末位加1
面向对象基础
面向对象和面向过程的思想对比
面向对象是基于面向过程的
面向过程编程 POP
是一种以过程为中心的编程思想.实现功能的每一步,都是自己实现
面向对象编程 OOP
是一种以对象为中心的编程思想,通过指挥对象实现具体的功能
对象:
指客观存在的事物,都可以看成程序中的对象( 万物皆对象)
使用面向对象思想可以将复杂的问题简单化
将我们从执行者的位置,变成了指挥者
类和对象
类是对现实生活中一类具有共同属性和行为的事物的抽象
类是对事物,也就是对象的一种描述.
类是对象的设计图,对象是类的实例
根据类,可以创建出一个具体的对象
类的组成
属性: 该对象的各种特征
在代码中通过成员变量来体现,属性在类中方法外
行为:该对象存在的功能
通过成员方法来实现
public class Student {
//属性:姓名,年龄
//成员变量:跟之前定义变量的格式
private String name;
private int age;
//行为:学习
//成员方法:跟之前定义方法的格式一样,只不过去掉了static
public void study(){
System.out.println("学习");//这里可以实现一个功能
}
对象的创建
public static void main(String[] args) {
//对象的创建 类名 对象名=new 类名();
// Student s=new Student();
Student student=new Student();
/*
因为成员变量的私有化,在其他类中不能直接用(对象名.变量名)调用
调用对象 对象名.变量名
System.out.println(student.name);
System.out.println(student.age);
成员变量的赋值
student.name="张三";
student.age=18;
System.out.println(student.name);
System.out.println(student.age);
*/
//使用set和get方法来赋值或者调用成员变量
System.out.println(student.getName());
System.out.println(student.getAge());
student.setName("张三");
student.setAge(18);
System.out.println(student.getName());
System.out.println(student.getAge());
student.show();
}
垃圾回收机制
当堆内存中,对象或数组产生的地址,通过任何方式都不能被找到后,就会被判定为内存中的**“垃圾”**,垃圾会被java垃圾回收器,空闲的时候自动进行清理
成员变量和局部变量
成员变量:类中方法外
局部变量:方法形参,方法内的变量
private关键字
权限修饰符,私有化成员变量,成员变量只能在本类中直接访问
this关键字
局部变量和成员变量如果重名,Java使用的是就近原则
this关键字的作用:
可以调用本类的成员(变量,方法),解决局部变量和成员变量的重名问题
代表所在类对象的引用,方法被哪个对象调用,this就代表哪个对象
封装
面向对象三大特征之一(封装,继承,多态)
隐藏实现细节,仅对外暴露公共的访问方式
封装常见的体现:
私有化成员变量,提供set和get方法
将代码抽取到方法中,这是对代码的一种封装
将属性抽取到类中,这是对数据的一种封装
构造方法
-
构建,创造对象的时候,所调用的方法
-
格式:
方法名与类名相同,大小写也要一致
没有返回值类型,连void也没有
没有具体的返回值(不能由return带回结果数据)
-
执行时机:
- 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
- 不能手动调用构造方法
构造方法的作用
用于给对象的数据(属性)进行初始化
构造方法注意事项
如果没有定义构造方法,系统将给出一个默认的无参构造方法
如果定义了构造方法,系统将不在提供默认的构造方法
构造方法的重载,如果定义了带参构造方法,还要使用无参构造方法,那就必须再写
一个无参构造方法
专门封装数据的类 : JavaBean类
继承
描述:父类可以有多个子类,子类只能继承一个父类,继承是多态的前提
继承解决的主要问题:共性抽取
继承关系当中的特点:
1.子类可以拥有父类的内容
2.子类还可以拥有自己专有的内容
继承关键字: extends
设计原则:
对于已经投入使用的类,尽量不要修改,推荐定义一个新的类,重复利用其中共性内容
并且添加新内容。
super关键字的用法有三种
1. 在子类的成员方法中,访问父类的成员变量。
2. 在子类的成员方法中,访问父类的成员方法。
3. 在子类的构造方法中,访问父类的构造方法。
this关键字的用法
1.在本类的成员方法中,访问本类的成员变量。
2.在本类的成员方法中,访问本类的另一个成员方法。
3.在本类的构造方法中,访问本类的另一个构造方法。
在第三种用法当中要注意:
this(…)调用也必须是构造方法的第一个语句,唯一一个。
super和this两种构造调用,不能同时使用。
注意:
成员变量和成员方法的调用都遵循就近原则
方法重写()
继承的特点
1. Java语言是单继承,一个类的直接父类只能有唯一一个
2. Java语言可以多级继承。A --》B extends A --》C extends B
3. 但是一个父类可以拥有很多个子类。A --》 B extends A C extends A ......
抽象类和抽象方法
/*
抽象方法:就是加上abstract关键字,去掉大括号,直到分号结束
抽象类:抽象方法所在的类,必须是抽象类。在class之前加上abstract即可
抽象类中也可以定义普通成员方法
如何使用抽象类和抽象方法:
1.不能直接new抽象类对象
2.必须用一个子类来继承抽象父类
3.子类必须覆盖重写父类当中的所有抽象方法
覆盖(实现):子类去掉抽象方法的abstract关键字,补上大括号方法体
*/
public abstract class Animal {
//这是一个抽象方法,代表吃东西,具体吃什么不知道
public abstract void eat();
}
一个抽象类不一定含有抽象方法
只要保证抽象方法所在的类是抽象类,即可
没有抽象方法的抽象类,也不能直接创建对象,在一些特殊的场景下有用途
static关键字
被static修饰的成员,会被该类的所有对象所共享
被static修饰的成员,会随着类的加载而加载,优先于对象存在
多了一种调用方式,通过 类名.成员变量(方法) 调用
静态方法只能访问静态方法、静态变量;不能访问非静态
静态方法中不能有this关键字
分包思想与分类思想
分包思想
如果将所有类文件都放在同一个包下,不利于管理和后期维护
对于不同功能的类文件,可以放在不同的包下进行管理
包的存在
1、有利于类的查找与管理,按自己的需要给包分类,通常按功能分:vo类、dao类、工具类、service类、controller类等。
2、解决了类命名时相同的冲突,在同一文件夹里不能同时定义名字相同的两个文本文档,java中也是,不能在同一包里定义两个相同类名的类,但是不同包就可以。
3、保护类中成员变量及其方法。该变量和方法的使用范围取决于访问控制符。
包的命名规则:
1、全部由小写字母
2、包含多层次应用“.”分割
3、一般由倒置的域名开头
4、自定义包不能以java开头
package关键字定义包
package com.itheima.entry;
类与类之间的访问
同一个包下的访问
不需要导包,直接使用
不同包下的访问
import导包后访问
通过全类名(包名+类名)访问
注意:
package必须是程序的第一条可执行代码
import需要写在package下面
class需要在import下面
引包的情况:
1、在自定义类中使用在不同包中其他自定义类时
2、使用除java.lang包外,其他包中的jdk中的类需要引包
3、使用第三方jar包中的类或接口时需要引包
分类思想
分工协作,专人干专事
提高代码的维护性,可读性以及复用性
- 实体类 标准类,封装数据的类
- dao类 Dao(Data Access Object缩写),用于访问存储数据的数组或集合的类
- service类 用来进行业务逻辑的处理
- controller类 用来和用户打交道
用户 -请求-> controller --> service --> dao --> 数据集合或数组
用户 <-回复- controller <-- service <-- dao <-- 数据集合或数组
final关键字
final修饰基本数据类型的变量时,该变量只能初始化一次并且不能重新赋值
final修饰引用数据类型的变量时,该变量内的元素值可以改变,地址值不能被改变
final修饰的方法不能被子类重写
final修饰的类不能被继承,称为终态类
代码块
在Java中,使用{}括起来的都被称为代码块
分类:
- 局部代码块
- 位置:方法中定义
- 作用:限定变量的生命周期,及早释放,提高内存利用率
- 构造代码块
- 位置:类中方法外
- 特点:每次构造方法执行时,都会执行该代码块中的代码,并且在构造方法执行前执行
- 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
- 静态代码块
- 位置:类中方法外定义
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次,多个静态代码块
- 与一个静态代码块是一样的
- 作用:在类加载的时候做一些数据初始化的操作
方法重写
在继承体系中,子类出现和父类一模一样的方法声明
方法重写的应用场景3
- 当子类需要父类的功能,而功能主体子类有自己特有内容,可以重写父类当中的方法,即沿袭了父类的功能,又定义了子类特有的内容(方法名,参数列表,返回值类型必须一致)
方法重写注意事项
-
父类私有方法不能被重写
-
父类非静态方法,子类也必须通过非静态方法进行重写
-
静态方法不能被重写!如果子类中,也存在一个和父类一模一样的静态方法,可以理解为,子类将父类中同名的方法,隐藏了起来,并非是方法重写
-
子类重写父类方法时,访问权限必须大于等于父类
修饰符 | 同一个类中 | 同一个包中子类与无关类 | 不同包的子类 | 不同包的无关类 |
---|---|---|---|---|
private | 可访问 | |||
默认 | 可访问 | 可访问 | ||
protected | 可访问 | 可访问 | 可访问 | |
public | 可访问 | 可访问 | 可访问 | 可访问 |
mysql数据库下载地址:https://download.mysql.com/archives/community/
接口
Java接口是一系列方法规范的集中说明,这些方法通常只有方法特征没有方法体
成员变量
接口的成员变量默认加上了 public static final修饰,所以接口中的成员变量都是常量
构造方法
接口中没有构造方法
成员方法
接口中的方法访问权限(不写)默认都加上了public
jdk1.8之后接口中有抽象方法、默认方法、静态方法、私有方法
默认方法解决了接口升级问题
静态方法通过接口名调用
私有方法是为了不同方法中相同代码块的抽取
public interface 接口名{}
public class 实现类名 implements 接口名 1,2,3,4...、{ }
定义:接口的存在是为了实现程序的可扩展性。
存在意义:如果你的类的结构体系中,某一个类要扩充功能怎么办?那么我们就要去修改这个类的父类甚至说是超类吗?这显然不合理。(而且如果你使用别人提供的类,根本就不可能去修改它)也许你要一直追溯到Object都不行。可是使用接口,你想给这个体系中的某个类扩充功能,只需要给这个类实现一个新的接口,自然就会提供新的功能,丝毫不会影响它的超类,而它的子类自动也扩充了它新增加的这个接口的方法(有点象C++多继承)。这使的软件的功能扩展变得更容易。设计模式中有一条开闭原则,说:软件实体必须都修改关闭,对扩展开放。使用接口,就可以满足这样的设计要求。
应用场景:该类下某些子类需要该方法而有一些则不需要,那么就在需要的子类下接入接口即可
多态
多态的使用场景:有继承或者实现关系,有方法重写
当定义一个方法,方法的参数写成父类,调用方法是可以传递任意的子类对象
多态的含义:一个子类对象在不同时刻表现出的多种状态
多态的成员访问特点
成员变量
编译看左边,运行看左边
成员方法
编译看左边,运行看右边
访问特点不一样的原因:成员变量无重写,方法有重写
多态的弊端与好处
好处:提高了程序的扩展性,定义方法时,父类类型作为参数,该方法就可以接收任意的子类对象
弊端:不能使用子类特有的内容
解决:1.直接创建子类对象
2.向下转型
从父类类型转换回子类类型可能出现ClassCastException,避免出现问题可使用 instanceof关键字,判断关键字左边的对象引用是否是右边的对象类型,返回结果 是boolean类型的结果
内部类
1.成员内部类
位置:类的成员位置
public class Outer{
class Inner{
public void show(){
System.out.println("show.....");
}
}
}
public class Test{
public static void main(String[] args){
//创建成员内部类对象
Outer.Inner oi=new Outer().new Inner();
oi.show();
}
}
2.局部内部类(方法中)
3.匿名内部类(精通,当需要一个子类对象又不想定义子类时)
前提:要有一个类/接口
格式:
new 接口/类(){
重写接口或类的抽象方法
}
本质:匿名内部类的本质是对象(是接口或类的子类对象)
interface Calculator{
public abstract int calc(int x,int y);
}
public class Test{
public static void main(String[] args){
int x=10;
int y=20;
userCalc(new Calculator(){//创建子类对象又不想定义子类
public int calc(int a,int b){
return a+b;
}
},x,y);
}
public static void useCalc(Calculator c,int x,int y){
int sum=c.calc(x,y);
System.out.println(sum);
}
}
lambda表达式
作用:Lambda表达式可以对匿名内部类的代码进行简化
使用前提:
要有函数式接口,并且只能有一个抽象方法
把函数式接口作为方法参数,别人调用方法时就可以传递Lambda表达式
interface Calculator{
public abstract int calc(int x,int y);
}
public class Test{
public static void main(String[] args){
int x=10;
int y=20;
//Lambda表达式
userCalc((int a,int b)->{return a+b;},x,y);
//简化写法,省略小括号中的数据类型,大括号,以及return和分号
userCalc((a,b)->a+b);
//如果接口方法只有一个参数
//userCalc(s->System.out.println("好好学习"))
}
public static void useCalc(Calculator c,int x,int y){
int sum=c.calc(x,y);
System.out.println(sum);
}
}
JavaAPI中常用的类
Math类:用于做数学运算
public static main(String[] args){
int a=-10;
//求绝对值方法 abs(),返回值类型int
int abs = Math.abs(a);
//四舍五入方法round(),返回值类型long
double b=3.44;
double b1=3.55;
long r1 = Math.round(b);
long r2 = Math.round(b1);
System.out.println(r1);//3
System.out.println(r2);//4
//向上取整 ceil(),
double d1 = Math.ceil(b);//4.0
System.out.println(d1);
// floor: 向下取整
double f1 = Math.floor(b1);
System.out.println(f1);//3.0
// max: 求最大值
double max = Math.max(b, b1);
System.out.println(max);//3.55
// min: 求最小值
double min = Math.min(b, b1);
System.out.println(min);//3.44
// random: 随机数
double rad = Math.random();//范围[0,1)之间的小数
System.out.println(rad);
}
System类:系统类
public static void main(String[] args) {
// currentTimeMillis: 获取当前系统时间的毫秒值(距离1970年1月1日0时0分0秒)
long timeStart = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
System.out.println(i);
}
long timeEnd = System.currentTimeMillis();
System.out.println(timeEnd-timeStart);
// arraycopy: 把一个数组复制到另一个数组中
String[] sArr={"h","e","l","l","o"};
String[] sArr1=new String[10];
System.arraycopy(sArr,0,sArr1,3,4);
for (int i = 0; i < sArr1.length; i++) {
// if (sArr1[i]!=null) {
System.out.print(sArr1[i] + " ");//null null null h e l l null //null null
// }
}
// exit: 退出虚拟机,非0为异常退出
System.exit(0);
}
Object类:是所有类的父类,任何一个类都可以使用它的方法
//toString: 把对象转换为字符串,建议子类重写
Student s1=new Student();
String s3 = Objects.toString(s1);//不重写打印地址值
//equals: 比较的是对象的地址,如果不想比较地址子类可以重写。
String str=new String("haha");
StringBuilder sb=new StringBuilder("haha");
System.out.println(str.equals(sb));//false
System.out.println(sb.equals(str));//false,SB中没有equals方法,去Object找,比 //较地址
Objects类:是一个工具类,用于对对象进行判空等操作
String s=null;
//isNull 等价于 i == null
boolean b=Objects.