一、Java语法基础
标识符: 用来标识类名、对象名、变量名、方法名、类型名、数组名、文件名的有效字符序列。
合法的标识符:由字母、数字、下划线“_”、美元符号“$”或者“¥”组成,并且首字符不能是数字。不能把java关键字和保留字作为标识符。标识符对大小写敏感。
关键字:Java语言中已经赋予了特定含义的
保留字: const、goto,Java版本中尚未使用,但以后版本可能会作为关键字使用
变量:程序运行期间可以被改变的量。在程序中使用变量,必须先创建它并为它取一个名字,并且指明它能够存储信息的类型,这称为“变量声明”,也叫容器的创建。
变量的使用:
- 变量的声明:数据类型 变量名;
- 变量的赋值:变量名 = 数据;
- 变量的操作:放入打印语句进行输出或者进行
运算Java 中的注释有三种:
- 单行注释
- 多行注释
- 文档注释
二、数据类型
引用数据类
Java的数据类型分为基本数据类型和引用数据类型,如图
基本数据类型除了字符型和布尔型之外,其余6个都是表示数字的,统称“数值型”。每种基本数据类型在内存中的存储方式和占用空间都不同,数据类型占用空间表如图
三、运算符
- 算术运算符
- 关系运算符
- 赋值运算符
- 逻辑运算符
- 位运运算符
- 三元运算符
- 运算符的优先级
1、算术运算符:算术运算符是Java中最简单、最常用的运算符,它主要提供了数值的加、减、乘、除以及求余运算的功能。算术运算符分为一元运算符和二元运算符,如图
2、关系运算符:当需要比较两个数值的大小时,可以使用关系运算符。关系运算符也称作比较运算符,关系运算符的运算结果为布尔类型,如图
3、赋值运算符:赋值运算符的作用就是将常量、变量或表达式的值赋给某一个变量。它将运算符右边的值赋给左边的变量。在Java中,将赋值运算符与算术运算符进行了合并,提供了更简洁的扩展赋值运算符。扩展赋值运算符的作用是简化一部分代码的书写,如图
4、逻辑运算符:逻辑运算符用于连接多个布尔值,一般与比较运算符一起使用,表示与、或、非的关系逻辑运算符,如图
5、位运算符:虽然高级编程语言中都提供了算术运算符,但实际上计算机中的计算都是二进制的,这意味着使用算术运算符虽然简单,但存在着性能的损失。而位运算是直接对二进制进行的计算,性能极高,很多框架中都会使用位运算。位运算符如图
6、三元运算符:三元运算符又称三目运算符,是连接三个表达式的运算符,语法格式如下。
条件表达式?表达式1:表达式2;
当条件表达式为true时,执行表达式1,否者执行表达式2。三元运算符可用于一些简单的逻辑判断,比如获取两个数中的最大值。
7、运算符的优先级
在实际开发中,可能同时使用到多种运算符,而运算符之间的优先级是不同的,优先级越低的运算符越先执行。运算符的优先级去图
四、数组
1、数据的概述
数组是数据的集合,一个容器,用来存储任何类型的数据,包括原始数据类型和引用数据类型,但是一旦指定了数组的类型之后,就只能用来存储指定类型的数据。
数组声明的三种方式:
- 数据类型[] 数组名 = new 数据类型[长度];
- 数据类型[] 数组名 = {数据,数据,…,数据};
- 数据类型[] 数组名 = new 数据类型长度[] {数据,数据,…,数据};
其中,数据类型可以是任意的基本数据类型和引用类型。
2、数组的常见操作
- 通过索引操作元素
- 数组的遍历
- 获取数组的最值
- 通过值获取索引
- 数组元素的反转
3、数组排序算法
- 冒泡排序
- 选择排序
4、数组类型
一维数组:
- 数组变量的声明:语法:数据类型[] 数组名;,如:int[] num;、double[] d;、String[] str;
- 数组对象的创建:语法:数组名 = new 数据类型[长度];,如:num = new int[4];
- 数组声明其长度后不可改变赋值:语法:数组名[下标] = 数据;,如:num[0] = 3;
- 数组元素的使用及遍历:语法:数组名[下标],获取指定下标是数据。
二维数组:
- 数组变量的声明:语法:数据类型[][] 数组名;,如:int[][] num;、double[][] d;、String[][] str;
- 数组对象的创建:语法:数组名 = new 数据类型[外长度][内长度];,如:num = new int[4][3];
- 数组声明其长度后不可改变赋值:语法:数组名[外下标][内下标] = 数据;,如:num[0][0]= 3;
- 数组元素的使用及遍历:语法:数组名[外下标][内下标],获取指定下标是数据。
五、Java流程控制语句
1、选择结构
if语句: if(条件表达式){ 一条或多条语句 };
if else语句: if(条件表达式) {语句块1} else {语句块2}
if多分支语句:
switch开关语句:
2、循环结构
在程序中当要重复性的做某项工作时可以使用循环语句,包括:for循环、while循环、do…while循环。
for循环语句:
while循环语句:
do…while循环语句:
3、流程跳转
流程跳转语句:break,continue
- break:在switch中结束case条件判断,在循环体中结束循环
- continue:作用在循环体中,结束循环体的本次循环,而进入下次循环
六、面向对象概述
1.1 面向过程和面向对象
1. 面向对象:Object Oriented Programming面向过程,强调的是功能行为,以函数为最小单位
2. 面向过程:Procedure Oriented Programming面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
3. 面向对象的三大特征
- 封装 (Encapsulation)
- 继承 (Inheritance)\n多态 (Polymorphism
- 把大象装到冰箱的面向对象设计和面向过程设计如下
1.2 概述类(Class)和对象(Object)是面向对象的核心概念。
- 类是对一类事物的描述,是抽象的、概念上的定义
- 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
- 可以理解为:类 = 抽象概念的人;
- 对象 = 实实在在的某个人 面向对象程序设计的重点是类的设计
- 类的设计,其实就是类的成员的设计
1.3 类的成员
现实生物世界中的细胞又是由什么构成的呢?细胞核、细胞质、… 那么,Java中用类class来描述事物也是如此。常见的类的成员有:
- 属 性:对应类中的成员变量
- 行 为:对应类中的成员方法\nField = 属性 = 成员变量,Method = (成员)方法 = 函数
public class Person {
String name;
int age;
/**
- sex:1 表明是男性
- sex:0 表明是女性
*/
int sex;
public void study(){
System.out.println("studying");
}
public void showAge(){
System.out.println("age:" + age);
}
public int addAge(int i){
age += i;
return age;
}
}
1.4 内存解析
1. 创建对象
class Person{
int age;
void shout(){
System.out.println(“oh,my god! I am ” + age);
}
}
Person p1 = new Person();执行完后的内存状态。其中类定义如下:
2.使用对象
class PersonTest{
public static void main(String[] args) { //程序运行的内存布局如下图
Person p1 = new Person();
Person p2 =new Person();
p1.age = -30;
p1.shout();
p2.shout();
}
}
3.内存区域
- 堆(Heap),此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内 存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
- 通常所说的栈(Stack),是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译 期可知长度的各种基本数据类型(boolean、byte、char 、 short 、 int 、 float 、 long 、double)、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址)。 方法执行完,自动释放。
- 方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
4.代码分析
class Person{//人类
//1.属性
String name;//姓名
int age = 1;//年龄
boolean isMale;//是否是男性
}
class PersonTest{
main(){
Person p = new Person();
Person p1 = new Person();
p1.name = “Tom”;
Person p2 = p1;
}
}
class Car{
String color = "red";
int num = 4;
void show(){
System.out.println("color="+color+"..num="+num);
}
}
class CarTest {
public static void main(String[] args) {
Car c1 = new Car(); //建立对象c1
Car c2 = new Car(); //建立对象c2
c1.color = "blue"; //对对象的属性进行修改
c1.show(); //使用对象的方法
c2.show();
}
}
1.5 属性(Field)
1. 变量的分类
- 在方法体外,类体内声明的变量称为成员变量。
- 在方法体内部声明的变量称为局部变量。
2. 成员变量默认初始化值
public class Person {
private int i;
short s;
private char c;
String str;
int[] arr;
@Override
public String toString() {
return ""+ i + s + (int)c + str + arr;
}
public static void main(String[] args) {
System.out.println(new Person());
}
}
//结果 000nullnull
1.6 方法(Method)
- 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
- 将功能封装为方法的目的是,可以实现代码重用,简化代码
- Java里的方法不能独立存在,所有的方法必须定义在类里。
格式:
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
方法体程序代码
return 返回值;
}
计算圆面积:
/*
* 2.利用面向对象的编程方法,设计类Circle计算圆的面积。
*/
//测试类
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
c1.radius = 2.1;
//对应方式一:
// double area = c1.findArea();
// System.out.println(area);
//对应方式二:
c1.findArea();
}
}
//圆
class Circle{
//属性
double radius;
//求圆的面积
//方式一:
// public double findArea(){
// double area = Math.PI * radius * radius;
// return area;
// }
//方式二:
public void findArea(){
double area = Math.PI * radius * radius;
System.out.println("面积为:" + area);
}
}
1.6.1 方法的重载
- 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
- 重载的特点:与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。
- 调用时,根据方法参数列表的不同来区别。
//返回两个整数的和
int add(int x,int y){return x+y;}
//返回三个整数的和
int add(int x,int y,int z){return x+y+z;}
//返回两个小数的和
double add(double x,double y){return x+y;}
public class PrintStream {
public static void print(int i) {……}
public static void print(float f) {……}
public static void print(String s) {……}
public static void main(String[] args) {
print(3);
print(1.2f);
print("hello!");
}
}
1.6.2可变参数
- 声明格式:方法名(参数的类型名 …参数名)
- 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
- 可变个数形参的方法与同名的方法之间,彼此构成重载
- 可变参数方法的使用与方法参数部分使用数组是一致的
- 方法的参数部分有可变形参,需要放在形参声明的最后
- 在一个方法的形参位置,最多只能声明一个可变个数形参
1.6.3 参数传递
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
- 形参:方法声明时的参数
- 实参:方法调用时实际传给形参的参数值
Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
- 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
1.基本数据类型参数传递
public static void main(String[] args) {
int x = 5;
System.out.println("修改之前x = " + x);
// x是实参
change(x);
System.out.println("修改之后x = " + x);
}
public static void change (int x){
System.out.println("change:修改之前x = " + x);
x = 3;
System.out.println("change:修改之后x = " + x);
}
2.引用参数传递
public static void main(String[] args) {
Person obj = new Person();
obj.age = 5;
System.out.println("修改之前age = " + obj.age);
change(obj);
System.out.println("修改之后age = " + obj.age);
}
public static void change(Person obj) {
System.out.println("change:修改之前age = " + obj.age);
obj.age = 3;
System.out.println("change:修改之后age = " + obj.age);
}
其中Person类定义为:
class Person{
int age;
}
1.6.4 递归方法
递归方法:一个方法体内调用它自身
- 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
2.1面向对象的基础
2.1.1面向对象-三大特性
面向对象的三大特性是封装、继承、多态
2.1.2封装
1.为什么要封装?
- 直接在对象的外部为对象的属性赋值,并没有对属性的赋值加以控制,就可能存在非法数据的录入。
2.封装作用:
- 减少耦合
- 类内部的结构可以自由修改
- 对其成员进行更精确的控制
- 隐藏信息,实现细节
3.什么是封装?
概述:隐藏对象的属性和内部实现细节,仅对外提供公共访问方法,控制对象的修改及访问的权限。
4.封装的原则
- 将不需要对外提供的内容都隐藏起来
- 属性一般用private修饰
- 私有属性由get/set方法进行读取和赋值操作,boolean类型的get方法改为is开头
- 要访问被封装的私有属性,必须通过set、get方法
- 除了只在本类使用的方法用private修饰外,其他方法都使用public修饰
5.封装的实现步骤
(1)用private关键字把属性设置为私有
(2)提供公共的setter和gette方法,用public修饰
(3)通过setter方法对输入的数据进行过滤
小提示:调用get、set方法时,get方法可以直接放在输出语句中,set不可以
如何防止构造器破坏封装:
当我们定义了有参构造器时,别人可以直接通过构造器进行赋值,从而绕过set方法的校验
2.1.3继承
1.概述:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
2.定义:子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
- 两个类之间的继承关系,必须满足“is a”的关系。
- 可以使用IDEA中的类图来查看类之间的关系
IDEA类图的字段与属性的区别
- 字段:就是平时所说的成员变量(属性)
- 属性:特指以set或get开头的方法,提取set或get后面的名称当做属性
3.继承的作用
继承设计思想:
- 父类构造器完成父类属性的初始化
- 子类构造器完成子类属性的初始化
好处:
- 强代码的复用性,更容易实现类的扩展(多个类相同的成员可以放到同一个类中)
- 提高了代码的可维护性(如果某功能的代码需要修改,只需修改一处即可),方便对事务建模
- 让类与类之间产生了关系,是多态的前提,这里其实也是继承的一个弊端:类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
开发的原则:低耦合,高内聚
- 耦合:类与类的关系
- 内聚:自己完成某件事情的能
4.继承的特点
- Java是单继承,一个子类只能有一个直接父类,但是可以多层级间接继承其他父类的属性和方法,一个父类可以有多个子类(使用接口可以实现多继承)
- 子类只能继承父类所有非私有成员(成员方法和成员变量),但是可以通过非私有成员访问父类的私有成员,这里其实也体现了继承的另一个弊端:打破了封装性。所以,不要为了部分功能而去继承
- 子类不能继承父类的构造方法(构造方法名必须与类名一致,继承之后子类名与父类构造方法名称不一致),但是可以通过super关键字去访问父类的构造方法
- Java中所有类的父类都是Object类,即如果不使用extends标明继承的直接父类,则系统默认该类的直接父类是java.lang.Object类
- 有些语言是支持多继承的,格式:class 子类名 extends 父类名1,父类名2…{}
2.1.4多态
概述:某一个对象(事物),在不同时刻表现出来的不同状态(或者说:同一个方法由于调用对象的差异导致不同的行为),注意:多态是方法的多态,而不是属性的多态,即多态与属性无关
如学生对象在不同时刻的身份:
1、多态的前提:
- 存在继承关系
- 父类方法被子类方法重写
- 父类引用指向子类对象: 父类 引用名 = new 子类();
2、多态的利弊
好处:
- 一致的类型:所有子类对象都可以当作共同(共有)的父类对象来处理
- 多态的优势主要提现在向上转型
- 提高了程序的可扩展性(由多态保证)
- 使用父类作为方法形参实现多态,使方法参数的类型更为宽泛
- 使用父类作为方法返回值实现多态,使方法可以返回不同子类对象
- 提高了程序的可维护性(由继承保证)
弊端:
- 不能访问子类特有的方法。因为编译的时候主要看左边的类型,左边是父类型,所以不能访问子类型特有的方法。
3、多态的转型
- 前面提到了,多态有一个弊端,那就是不能访问子类特有的方法,这里可以利用向下转型解决这个问题