编译和运行
在java安装路径下打开bin文件夹,使用javac.exe程序编译一个java文件,编译结果是一个class文件(字节码文件)。class文件是给机器读的,用java.exe运行一个字节码文件。
javac Helloworld.java
java Helloworld.class
版本
java更新速度极快,不便于学习,开发者把java分为两个两种版本,一种是过渡版本,一种是长期支持版本(正式版本,带有LTS后缀 Long Term Support),重要的正式版本中:Java5、Java8、Java17
三大使用平台:
也就是Java的三个分类,有JavaSE、JavaME、JavaEE
-
JavaSE
Java语言的标准版,用于桌面应用的开发,是其他两个版本的基础 -
JavaME
Java语言的小型版,用于嵌入式或小型移动设备 -
JavaEE
Java语言的企业版,用于Web方向的网站开发,服务器领域
特点
Java的主要特性:面相对象、安全性、多线程、简单易用、开源、跨平台
Java跨平台原理:Java是混合型语言,它是先把.java编译成.class,然后在运行的时候解释成机器码
JDK和JRE
Java编写和运行需要:JVM(Java虚拟机,真正运行Java程序的地方),核心类库、开发工具(javac编译工具、java运行工具、jdb调试工具、jhat内存分析工具)
JVM、核心类库、开发工具称为JDK(Java开发工具包)
如果只需要运行代码(class文件),只需要JVM和核心类库,这两个组成了JRE,就是Java的运行环境包,大小比JDK小
Java基础
数据类型
基本数据类型
分为四类、八种:
整数:byte、short、int、long
浮点数:float、double
字符:char
布尔:boolean
如果要定义long类型的变量,要在数据值后面加一个L作为后缀,L大写和小写都可以,建议用L(区分l和1)
如果用float需要加F,double不需要
char接收一个字符,用单引号包裹
引用数据类型
引用数据类型的变量中存储的是地址值,引用:使用了其他空间中的数据
键盘录入
import java.util.Scanner; // 导包操作写在类定义之前
Scanner sc = new Scanner(System.in); // 实例一个Scanner对象
int i = sc.nextInt(); // 让用户输入,获取整数
IDEA项目结构
project项目、module模块、package包、class类
隐式转换和强制转换
不同的数据类型是不能相互运算的,取值范围小的类型和大的类型运算会把小的提升为大的再运算。
byte、short、char类型在运算时,都会提升为int类型运算。char根据ASCLL码提升为int
强制转换格式:目标数据类型 变量名 = (目标数据类型)被强制转换的数据;
逻辑运算符
&
逻辑与、|
逻辑或、&&
短路逻辑与、||
短路逻辑或
&
和|
不带有短路效果,短路效果可以带来效率提升
位运算符
<<
左移,>>
右移
数组
静态初始化
格式:数据类型[] 数组名 = new 数据类型[] {元素1, 元素2, 元素3}
简化格式:数据类型[] 数组名 = {元素1, 元素2, 元素3};
int[] arr1 = new int[]{
1, 2, 3};
int[] arr2 = {
1, 2, 3};
如果直接输出数组,会输出改数组的地址,例:[I@4eec7777
数据类型[] 数组名 = new 数据类型[数组长度]
指定初始化数组长度
int[] arr2 = new int[10];
改数组由虚拟机给出初始值:
整数类型:0、小数类型:0.0、字符类型:'\u0000’空格、布尔类型:flase、引用数据类型:null
数组的内存
在内存中,栈用来存储方法运行时的内存,比如main方法运行,进入栈中执行。堆用来存储new创建的对象或者数组
new 出来的一定是在堆内存中开辟了空间,栈内存中存储的是堆内存的地址值。
如果arr1是new出来的数组,数组arr2的值是arr1,那么没有new,就不会再堆中开辟一个空间,arr1和arr2都是指向那一个堆中的空间
方法
方法(method)是程序中最小的执行单元。
方法用来提高代码复用性和维护性
重载
构成重载需要满足下列要求:
- 在同一个类中
- 具有不同参数类型或参数个数
方法的值传递
如果传递的是基本数据类型,那么在传递值的时候是复制数据给方法,传递和接收的数据的地址不同,所以在方法中修改里面的内容不会影响调用的时候的值。
如果传递的是引用数据类型,传递值的时候传递的是数据的地址,传递和接收的数据的地址相同,所以在方法中修改里面的内容会影响调用的时候的值。
面向对象
面相对象三大特性:封装、继承、多态
类和对象
类是共同特征的描述,对象是真实存在的具体实例
类需要声明,对象通过new一个类得到。
访问权限
默认为default,空着不写就是default
private : Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
default: 即不加任何访问修饰符,通常称为“默认访问权限“或者“包访问权限”。该模式下,只允许在同一个包中进行访问。
protected: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护访问权限”。被其修饰的属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问。
修饰符 | 同一个类中 | 同一个中其他类 | 不同包下的子类 | 不同包下的无关类 |
---|---|---|---|---|
private | true | false | false | false |
default | true | true | false | false |
protected | true | true | true | false |
public | true | true | true | true |
定义类的注意点
用来描述一类事物的类,专业叫做:Javabean类。在Javabean类中是不写main方法的
在以前写main方法的类叫做测试类。可以在测试类中创建javabean类的对象进行赋值调用
类名首字母建议大写、英文、有意义,满足驼峰模式,不能用关键字,满足标识符规定
一个代码文件中可以定义多个类,但是只能有一个类是public修饰,public修饰的类名必须是java代码的文件名称
成员变量和成员方法
在类中定义的变量是成员变量,在类中定义的方法是成员方法。
public class Person {
private String name; // 成员变量
public String say(String meg) {
String name; // 局部变量
System.out.println(meg); // 局部变量
System.out.println(this.meg); // 成员变量
}
}
如果想要访问成员变量,要用this
关键字获取实例后的对象,通过this.name
获取成员变量
成员变量和局部变量的区别:
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置不同 | 类中、方法外 | 方法内、方法上 |
初始化值不同 | 有默认初始化值 | 没有默认初始化值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,对象消失时销毁 | 随着方法的调用而存在,方法运行结束时销毁 |
作用域 | 整个类中有效 | 当前方法中有效 |
类的封装
在类中定义的成员方法要public公开,要private私有成员变量,并提供对应的getter和setter,也就是获取和设置这个变量值的方法
public class Person {
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0) System.out.println("非法age");
else this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
if (sex.equals("男") || sex.equals("女")) this.sex = sex;
else System.out.println("非法sex");
}
}
构造方法
创造对象的时候(new的时候),虚拟机会自动调用构造方法,用来给成员变量进行初始化
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
Person abc = new Person("张三");
如果没有定义构造方法,系统会给出一个默认的无参构造方法,如果定义了构造方法,系统不再提供默认构造方法
构造方法的重载:构造方法名相同,参数不同就是构造方法的重载
推荐:无论是否使用,都写一个无参构造方法,和带全部参数的构造方法
标准的JavaBean类
类名需要见名知意,成员变量使用private修饰,提供至少两个构造方法(无参构造、全参构造),成员方法(提供每一个成员变量对应的getter和setter,如果有其他方法要写上)
this
this指的是所在方法调用者的地址值。它是一个局部变量。
例:
public class Person {
private String name;
private int age;
private String sex;
public Person() {
}
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
/**
* 获取
*
* @return name
*/ public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/ public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
*
* @return sex
*/ public String getSex() {
return sex;
}
/**
* 设置
*
* @param sex
*/
public void setSex(String sex) {
this.sex = sex;
}
}
Person abc = new Person("牛逼", 18, "男");
abc.setSex();
这里的setSex中的this
指的是实例对象abc的地址,使用堆空间的这个abc实例对象的地址区域中的变量sex
static
static关键字可以用来修饰成员变量或成员方法,将其静态化。
静态成员变量跟实例对象无关,他在类初始化之后,类实例对象之前就生成于堆内存的静态区。所以静态方法不能调用非静态属性和方法。非静态方法可以调用静态属性和方法。
使用静态属性和方法在类或对象上使用都可以,但是建议在类上调用,例:Person.resume
、Person.resume()
等
今天方法一般用于测试类和工具类,测试类就是带有main方法的用于测试别的类的类,工具类就是提供一些实用方法的类。
工具类的例子:
public class Math {
public static int max(int[] arr){
// ...
}
public static int min(int[] arr){
// ...
}
public static int avg(int[] arr){
// ...
}
}
继承
Java中提供一个关键字extends
,可以让一个类和另一个类建立继承关系
例如:Student为子类,Person为父类
public class Student extends Person {
// ...
}
使用继承的好处:可以把多个子类的重复成员变量和成员方法抽取到父类,提高代码复用性。
子类可以在父类的基础上,增加其他的功能,使子类更强大。
Java只能单继承,可以是a继承b,b继承c,那么a就是间接继承c
每一个类都直接或间接继承于Object(自己定义的类如果不写extends
继承某一个类,会自动继承Object类)
继承内容
父类的构造方法不能被子类继承
子类可以继承父类的成员变量,无论是私有还是非私有都可以在类中调用。但是对象不能直接使用私有的成员变量。
虚拟机在查找直接或间接父类时,从最顶级的父类开始创建一个虚方法表,里面存所有父类的虚方法,虚方法要满足下列条件:非private、非static、非final。使用虚方法表策略可以提高性能。
只有父类中的虚方法才能被子类继承
所以,父类的构造方法不能不被继承、成员变量可以被继承但如果是private则对象不能直接使用、在虚方法表中的成员方法可以被继承
成员变量和方法继承的特点
如果继承一个或多个父类,成员变量继承的是最近的一个父类的成员变量值。
super
关键字和this
类似,他在类中可以使用,表示的是父类的存储地址。this是本类,super是父类
super不可以super的属性:super.super
来获取父级的父级,只能获取直接父级
用this
或super
如果目标类中没有想要的值,会向父类查找
构造方法继承的特点
父类中的构造方法不会被子类继承,子类中所有的构造方法默认先访问父类的无参构造,再执行自己。
因为子类在初始化的时候,有可能用到父类中的数据,如果父类没有完成初始化,子类也无法使用父类数据。子类初始化之前,一定要调用父类的构造方法完成父类数据空间的初始化。
所以子类的构造方法的第一行默认语句都是super()
,不写也存在,且必须在第一行
如果想调用父类的有参构造,必须手写super()
调用,因为默认调用无参构造
如果在一个子类的空参构造中写上这个类的有参构造(用空参构造把默认值交给有参构造),虚拟机不会在空参构造上添加super()
,会在有参构造上添加:
public class Student{
public Student(){
this(null,0,"a"); // 第一行必须是构造,否则报错
}
public Student(String name, int age, String school){
// super();
// ...
}
}
方法的重写
根据成员变量和方法继承的特点,如果父类的方法不能满足子类的需求时,需要进行方法重写
在继承体系中,子类出现了和父类一模一样的方法声明,就称子类这个方法是重写的方法
在重写的方法上面要加上@Override
重写注解,校验子类重写时语法是否正确(代码安全、优雅)
重写的本质就是如果在虚方法表中出现了相同的方法,就会在该类的虚方法表中覆盖
注意事项:
- 重写方法的名称、参数要和父类一致
- 子类重写父类时,子类返回值类型和访问权限必须大于等于父类(返回值类型如果是引用数据类型,根据继承关系判断大小,父类大于子类)
- 私有和静态方法不能被重写(不在虚方法表中的方法不被重写)
建议:重写方法尽量和父类保持一致。
多态
多态就是同类型对象,表现出不同的形态
表现形式:父类类型 对象名称 = 子类对象;
多态的前提:有继承关系、有父类引用指向子类对象、有方法重写
例:
public class Test {
public static void main(String[] args) {
Student s = new Student(1, "A");
Teacher t = new Teacher(1