精品专题:
01.《C语言从不挂科到高绩点》课程详细笔记
https://blog.youkuaiyun.com/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482
02. 《SpringBoot详细教程》课程详细笔记
https://blog.youkuaiyun.com/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482
03.《SpringBoot电脑商城项目》课程详细笔记
https://blog.youkuaiyun.com/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482
04.《VUE3.0 核心教程》课程详细笔记
https://blog.youkuaiyun.com/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482
05. 《SSM详细教程》课程详细笔记
https://blog.youkuaiyun.com/yueyehuguang/category_12806942.html?spm=1001.2014.3001.5482
================================
|| 持续分享系列教程,关注一下不迷路 ||
|| 视频教程:墨轩大楼 ||
================================
1. 编程语言的发展史
1.1 机器语言
第一代计算机语言称之为机器语言,机器语言就是0/1代码。计算机只能识别0和1,在计算机的内部,无论一部电影,还是一首歌,一张图片,最终保存的都是0/1代码,以为CUP只能执行0和1,那么这就意味着我们的编程一定要用0和1来实现吗?
首先这么编写肯定是没有任何问题的,但是太麻烦了,而且还不好理解。所以就出现了汇编语言
1.2 汇编语言
汇编语言就是将一串很枯燥乏味的机器语言转为了一个英文单词。比如:
add 1,2;
mov
add就是一个英文单词,这样看起来就稍微的有了一些含义了,即1和2相加,这个就是汇编语言
通过专门的软件就可以将这些英文单词转化为0和1代码并由计算机执行,这种专门起到翻译作用的软件就叫做编译器
这些英文单词和他们对应的0和1代码之间的关系,以及语言的语法,在编写这个编译器的时候就已经写在里面了,我们只要通过编译器就可以将这些转化为0和1代码,这样大大的方便了我们对程序的编写。
1.3 高级语言
汇编语言之后又出现了第三代语言。第三代语言又叫“高级语言”。高级语言的发展分为两个阶段,以 1980 年为分界线,前一阶段属于结构化语言或者称为面向过程的语言,后一阶段属于面向对象的语言。
什么叫面向过程,什么叫面向对象?这是很难解释的一个问题,所以这个问题大家现在先不要考虑。等到将来你们学完C语言、C++、Java 或者 C# 之后才有可能理解。因为这个需要比较。
总之,面向过程语言中最经典、最重要的就是C语言。Fortran、Basic 和 Pascal 语言基本上已经很少有人使用了。但是C语言一直在用,因为C语言是计算机领域最重要的一门语言。但是C语言也有缺陷,它的缺陷只有在学完面向对象语言之后才能体会到。
所以从 20 世纪 80 年代开始又产生了另外一种“以面向对象”为思想的语言,其中最重要、最复杂的就是 C++。C++ 从易用性和安全性两个方面对C语言进行了升级。C++ 是一种较复杂、难学的语言,但是一旦学会了则非常有用。
因为 C++ 太复杂,所以后来就对 C++ 进行了改装,产生了两种语言,一个是 Java,另一个是 C#。
Java 语言是现在最流行的语言之一。C# 则是微软公司看 Java 很流行而写的一个与 Java 语法相似的语言。
编程语言的发展保持着一个原则
让变成更为简单,人性化
2. 面向对象编程
2.1 面向对象的思想
- 如果我们要吃一个蛋炒饭
方式一:打鸡蛋--->准备葱花--->起锅烧油--->米饭下锅翻炒--->鸡蛋下锅---->葱花下锅翻炒---->最后出锅,一碗蛋炒饭
方式二:找一个小摊儿,跟师傅说来一碗蛋炒饭,给钱,一会儿一碗蛋炒饭就完成了
方式一: 面向过程的炒饭,需要自己炒饭,自己一步一步的去完成步骤
方式二:面向对象的炒饭,不需要自己动手,别人去做
-
- 面向对象就是让复杂的问题简单化
- 面向对象把我们从执行者变为指挥者
- 面向对象可以把细节过程隐藏
- 面向对象编程 OOP
面向对象分析 OOA
面向对象设计 OOD
2.2 面向对象概述
面向对象: 将对问题的思考从传统过程化变为朝着人更容易理解的角度发展;
面向对象编程: 将现实生活中的一些事物或者需求,采用面向对象的一种方式编码进行实现;面向对象编程是一种抽象的思维
Java中万物皆对象
2.3 类和对象
2.3.1 什么是类?什么是对象?
分析一下
32岁的李大嘴厨师: 有姓名,有年龄,会烹饪
28岁的王大锤厨师: 有姓名,有年龄,会烹饪
22岁的Tony厨师: 有姓名,有年龄,会烹饪
1.他们都有共同的属性:姓名,年龄 共同的行为:烹饪!!!!!!!!!!
2.其中李大嘴,王大锤,Tony是具体存在的厨师
什么是类?什么是对象?
1.生活中都是由多种对象组成(万物皆对象,一切皆对象)
基于对象抽出了类
2.对象:真实存在的具体的单个个体
类:类别/类型 一类个体
3.类中包含:
所有对象共有特征/属性 ---------变量
所有对象共有的行为 ----------方法
4.一个类可以创建多个对象
同一个类创建出来的多个对象结构相同,数据不同
5.类是对象的模板,对象是类的具体实现
学生类
学生具备的一些属性信息:
学号
姓名
专业
班级
学分
学生具备的一些行为信息
学习
运动
小汽车品牌-----类
保时捷-----对象
帕拉梅拉----对象
女朋友-----类
我的女朋友----对象
2.3.2 类的语法定义
[访问修饰符] class 类名{
属性的定义
行为的定义
}
类的成分
属性:属性就是用于描述类的一些静态特征,又称之为类的数据,编码表示形式为变量的声明语法,这种变量一般为成员变量或者全局变量
int num;
String name;
行为:行为值得就是类的动态特征,通常的代码表现形式为方法(非static)
2.3.3 类的成分
一个Java类主要由三部分构成
- 属性属性使用与描述类的数据信息,声明语法
[修饰符] 数据类型 属性名 [=初始值]
private String name = "苍老师";
String sex;
int age = 18;
- 构造器构造器也叫做构造方法,建造器,用于在创建对象时执行一些初始化操作,语法
[修饰符] 类名([参数列表]){
//执行体
}
public class Student{
String name;
String sex;
int age;
//构造器,构造方法,建造器
public Student(){
name = "苍老师";
sex = "女";
age = 18;
}
}
注意:构造方法与普通方法的区别:构造方法没有返回值类型,也没有void,而且构造方法的方法名必须与类同名
- 方法方法表示的就是类所具备的行为特征
访问修饰符 返回值类型 方法名([参数列表]){
//方法体
}
public class Student{
/*属性*/
String name;
String sex;
int age;
//构造器,构造方法,建造器
public Student(){
name = "苍老师";
sex = "女";
age = 18;
}
//方法
public void study(){
System.out.println("这是一个学习的方法");
}
}
- 课堂练习分析学生具备的特征创建一个学生类学号姓名性别年龄专业学分入学年份学习的行为打游戏的行为谈恋爱的行为
2.3.4 对象的创建
对象的概述
以上类的声明已经清楚了,但是类总的来说还是一种抽象的概念;而面向对象编程的核心在于对象,所以需要通过类来获取对象
对象: 对象时类中的一个实例,对象是一种具体化的描述,例如:名字叫做张三的学生,车牌为鄂AF1025的汽车
类中所有的属性和行为需要被调用都是需要基于对象来完成
对象的创建
Java中创建对象的语法是使用一个new关键字
类名称 变量名 = new 类名称();
//上面创建了学生类,我们来创建一个学生对象
Student s1 = new Student();
//有了对象之后,我们就可以通过对象来调用属性和行为
s1.name = "佳文";
s1.study();
2.3.5 构造器
在创建对象时往往会使用
new 类名();
以上的类名() 就是构造器
Student s1 = new Student();
以上代码说明在Student类中存在一个Student() 构造器
使用构造器的时候要注意:
- 构造器的名称必须与类名一摸一样
- 构造器类似于方法的结构,但是不能定义任何类型的返回值,包括void
- 一个类中可以存在多个构造器,但是必须要求构造器的参数个数,顺序,类型任意一项不一致(构造器重载)
- 任何一个Java类都默认存在一个无参构造器
- 一旦我们自定义了构造器,那么默认的无参构造器就不再存在;那么如果你还需要使用无参构造器,那么你就需要重新显示的定义
练习
- 现需要完成一个电商系统,其中包含一个商品类(Goods),商品包含:编号(no),名称(name),单价(price),库存量(quantity),产地(area),以及打印商品信息的方法,要求创建以下三个不同构造器,并基于这三个构造器创建不同的对象:
-
- Goods(编号)
- Goods(编号,名称)
- Goods(编号,名称,价格)
- 另外再要求使用无参构造创建一个商品对象,并为商品的所有属性指定上具体的值,最后将所有的商品信息打印到控制台。
Goods.java
public class Goods {
int no;//编号
String name;//名称
double price;//单价
int quantity;//库存
String area;//产地
public Goods(){
}
public Goods(int gno){
no = gno;
}
public Goods(int gno,String gname){
no = gno;
name = gname;
}
public Goods(int gno,String gname,double gprice){
no = gno;// int no = 2
name = gname;
price = gprice;
}
public void show(){
System.out.println(no + "\t" + name + "\t"
+ price + "\t" + quantity + "\t" + area);
}
}
GoodsTest.java
public class GoodsTest {
public static void main(String[] args) {
Goods g1 = new Goods();
g1.no = 1;
g1.name = "康师傅牛肉面";
g1.price = 12.8;
g1.quantity = 10;
g1.area = "内蒙古";
g1.show();
Goods g2 = new Goods(2,"雪糕刺客",16.9);
g2.quantity = 20;
g2.area = "荆州";
g2.name = "哈根达斯";
g2.show();
}
}
3. 浅谈内存分配
public class Emp{
String name;
int age;
}
public class EmpTest{
public static void main(String[] args){
Emp emp1 = new Emp();
emp1.name = "张三";
}
}
堆内存
- 堆内存中包含了所有new出来的对象(包括成员变量)
成员变量:类的内部,方法的外部
- 成员变量的生命周期
创建对象的时候存在于堆中,对象被GC回收时随着对象一起销毁
- 堆内存中的垃圾: 没有任何引用(变量)指向的对象
垃圾回收机制(GC)不定时的到堆中去查看,看到有垃圾就回收,但是回收过程是透明的,并不是一有垃圾就立刻回收,若你想优先回收,你可以调用System.gc()方法来提高优先级
- 内存泄漏
不使用的对象没有及时回收
建议:当对象不再使用的时候,及时的将引用设置为null
public class People{
String name;
public People(){}
public People(String pname){
name = pname;
}
}
public class PeopleTest{
public static void change(People p){
p.name = "翠花";
}
public static void main(String[] args){
People p = new People("旺财");
System.out.println(p.name);//旺财
change(p);
System.out.println(p.name);//翠花
}
}
栈内存
- 用于存储正在被调用的方法以及所有正在调用的方法中的所有的局部变量以及参数列表中的变量
- 在调用方法时,栈空间中会自动的开辟一块儿对应的区域(栈帧),栈帧中就包含了该方法中所有的局部变量和参数列表中的所有变量,当方法调用结束时,栈帧自动消失,局部变量也随之消失
- 局部变量的生命周期
随着方法的被调用存在于栈帧中,随着方法调用的结束,随着栈帧一起销毁
关于成员变量和局部变量
- 类中的位置
-
- 成员变量在类中方法外
- 局部变量方法内部或者参数列表中
- 内存中的位置
-
- 成员变量在堆内存
- 局部变量在栈内存
- 生命周期
-
- 成员变量随着对象的存在而存在,随着对象的消失而消失
- 局部变量随着方法的调用而存在,随着方法调用结束而消失
- 初始值
-
- 成员变量有默认初始值
- 局部变量时没有默认初始值的,所以在使用局部变量时要先初始化
public class People {
String name;
public People(){}
public People(String pname){
name = pname;
}
}
public class PeopleTest {
public static void change(People peo){
peo.name = "翠花";
}
public static void main(String[] args){
People p = new People("旺财");
System.out.println("change前:" + p.name);//旺财
change(p);
System.out.println("change后:" + p.name);//翠花
}
}
关于方法参数的传递问题
- 基本数据类型传递的是数值
- 引用数据类型传递的是对象的地址
方法区
- 用于存储类的相关消息.class字节码文件(包括方法)
- 由于.class字节码文件只有一份,所以方法区中也存在一份,通过this来区分是哪一个引用所调用的
4. this关键字
this指代的是当前这个对象,哪个对象调用就指代哪个对象
this的用法
- this.成员变量 ----------------------->访问当前对象的成员变量在方法中访问成员变量的时候,只要局部变量的变量名于成员变量名不一样的时候,默认就有一个this.,当局部变量名与成员变量名一样时,则没有默认的this.了,那么就需要我们显示写出this.成员变量来区分,否则就是就近原则
- this.方法的签名 -------------------------->访问当前对象的方法
public void show(){
}
方法名 show
方法的签名 show()
- this构造器的参数列表----------------->访问当前对象的构造器(使用该方法时必须是在构造器的第一行,而且只能在这个位置用)
5. ArrayList使用与ArrayList实现原理
jdk内置提供了很多常见类:
java.lang.String
java.lang.Math
java.lang.System
java.util.Scanner
java.utils.ArrayList
5.1. 概述
由于java中数组的长度一经定义则无法修改,实际使用中存在一定的缺陷;因此java从java2开始引入的集合框架,其中提供了一个可变长数组的实现:ArrayList;该类内部使用了一个Object数组来存储任意的类型的元素,当向数组中添加的元素超出索引范围时,内部会使用扩容机制实现对数组的容量扩大(实际实现原理是:新建数组+数组拷贝实现)。
`ArrayList类允许向数组中存放任意类型,任意个元素,并且不会出现ArrayIndexOutOfBoundsException`,具体使用方法如下:
5.2. 常用构造方法
- ArrayList():构造一个初始长度为10的数组(实际容量是在调用add方法时才完成初始化)
- ArrayList(int capacity):构造一个指定长度的数组
5.3. 常用方法
- add(E e):添加一个元素到数组中
//传统数组设置元素的方式
int[索引] = 值;
//动态数组设置元素的方式
list.add(值)
- get(int index):获取指定位置的元素
//传统数组获取元素
int i = a[索引]
//动态数组获取元素
int i = list.get(索引)
- remove(int index):删除指定位置的元素
- size():获取数组中实际存储的元素个数
//传统数组获取长度的方式
int len = a.length;
//动态数组获取长度的方式(容器中真实存储的元素个数,并非实际数组长度)
int len = a.size()
- clear():清除数组中的所有元素
//传统数组清空的方式
a = new int[长度];
//动态数组清空的方式
a.clear();
5.4. 测试代码
//创建ArrayList对象 泛型:参数化类型(只能是引用数据类型)
ArrayList<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.remove(3);
list.clear();
list.size(); //数组中length
System.out.println(list);
注意事项:
- ArrayList默认支持任意数据类型的存储,但是如果需要限定数组中存储的数据类型,则可通过在ArrayList类定义时使用<类型名>的方式限定具体的数据类型,这种方法称之为泛型,后续集合部分深入研究.
- 不要在循环遍历ArrayList时删除或者修改元素,将会导致java.util.ConcurrentModificationException
6. package和import
6.1. package
package是java中一个常见的关键字,作用在于创建java类的时候为java类指定一个包路径;包的作用一般用来区分不同的模块,因为在一些大型项目中往往会由很多的java类协同工作,而不同的类具备不同的功能,因此将具备不同功能类分门别类的存储可以有利于代码的可维护性;另外包的作用也可以防止类名称重名的问题。包在本地磁盘的存储方式实际上就是一级一级的目录。
包的声明语法一般采用域名倒置写法:
//公司,盈利性机构
com.softeem.demo;
//国际化
cn.sina.xxx;
//个人或组织
org.mybatis.xxx;
//教育机构或者学校
edu.xxx.xxx;
//政府机关
gov.xxx.xx
pageckage一般出现在java类声明之外,java文件中的第一行
package com.softeem.oop.day2;
public class DynamicArray {
//...
}
6.2. import
在一个项目如果存在跨不同的包访问类时候,此时需要使用import导入指定类(或接口,枚举等)到当前的类(或者接口,枚举)中;
例如:
有如下类DynamicArray位于com.softeem.oop.day2包下
package com.softeem.oop.day2;
public class DynamicArray {
//...
}
现在需要在另一个包com.softeem.oop.day2.arraylist包中的类使用:
package com.softeem.oop.day2.arraylist;
//导入包
import com.softeem.oop.day2.DynamicArray;
public class Test {
public static void main(String[] args) {
DynamicArray da = new DynamicArray(); //此处会提示找不到类,通过在类上方使用import导入目标类所在的包即可解决
}
}
若在一个类中需要使用其他包中的多个类,可以一次性全部导入:
import com.softeem.oop.day2.*;
import的出现位置必须位于类的包定义和类定义之间
任何一个java类在编译时,编译器都会自动导入java.lang.*;
静态导包
对一些频繁需要使用的某个类的静态方法,在调用时通常都需要使用类名.方法名()调用,此时可以使用静态导包的方式,直接将该类中所有方法导入到指定类中,此时需要使用这些方法就无须通过类名称调用:
//静态导入Math类中的所有方法(静态方法)
import static java.lang.Math.*;
public class Test{
public static void main(String[] args){
//获取随机数
double d = random();
//获取最大值
int max = max(4,5);
}
}
7. 访问修饰符
Java中对于一些元素(属性,方法)的可访问性提供了四种范围:
- private 私有的
- default 默认的
- protected 受保护的
- public 公开的
同一个类中 | 同一个包中 | 子类中 | 全局 | |
private | true | false | false | false |
default | true | true | false | false |
protected | true | true | true | false |
public | true | true | true | true |
常用的访问修饰符主要为public 和private
全局指的是同一个项目中
一般情况下我们在使用访问修饰符的规则一般遵循:
- 属性私有化
- 行为公开化
8. 信息的隐藏与封装
8.1. 面向对象的程序设计语言的特点
面向对象程序设计语言中通常包含三大特征:
- 封装
- 继承
- 多态
- 抽象
8.2. 信息隐藏
在实际开发过程中对于某些Java类中的敏感信息,这些信息是希望外界无法随机访问,此时就需要使用一种机制来实现数据的隐藏;通常情况下需要隐藏的数据对象的信息,可以使用private 修饰符,将属性修饰为私有属性
public class User {
private String username;
private String password;
private int age;
private double money;
public User(String username,String password){
this.username = username;
this.password = password;
}
public User(String username,String password,int age,double money){
this.username = username;
this.password = password;
this.age = age;
this.money = money;
}
public User(){
}
public void setUsername(String username){
this.username = username;
}
public String getUsername(){
return this.username;
}
public void login(){
}
}
public class UserTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.getUsername());
u.setUsername("李二狗");
String name = u.getUsername();
System.out.println(name);
//u.username = "";
//u.password = "";
}
}
8.3. Setters&&Getters方法
通过上面对信息的隐藏之后,虽然信息是隐藏了,但是外界无法再直接使用属性赋值和获取值了,这种情况下实际开发过程中显然是不合理,所以我们需要提供公开的访问方法,单独的去为每一个属性设置值或者获取值,通常我们会使用Setter方法来设置值,Getter方法来获取值
7. 练习===动态日历
MyCalendar.java
public class MyCalendar {
private int year;
private int month;
public MyCalendar() {
}
public MyCalendar(int year, int month) {
this.year = year;
this.month = month;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
//显示日历
public void show(){
System.out.printf("======【%d】年【%d】月=====%n",year,month);
System.out.println("一\t二\t三\t四\t五\t六\t日");
//获取月初的空位数
int space = getTotalDaysFrom1900()%7;
//获取本月的天数
int days = getDaysOfMonth(month);
//声明一个变量用来计数
int count = 0;
//循环空格
for (int i = 0; i < space; i++) {
System.out.print("\t");
count++;
}
for (int i = 1; i <= days; i++) {
count++;
System.out.print(i+"\t");
if(count == 7){
count = 0;
System.out.println();
}
}
}
//获取1900年1月1号到当前月1号为止的总天数
/*
1900年1月1号周一
你需要的月份前面留多少个空位
1900.1.1到当前月1号为止的总天数除以7的余数
*/
public int getTotalDaysFrom1900(){
int days = 0;
//计算中途整年的天数
for (int i = 1900;i<year;i++){
days += isLeapYear(i)?366:365;
}
//计算你需要显示日历那一年那一月前面的天数
for (int i=1;i<month;i++){
days += getDaysOfMonth(i);
}
return days;
}
private int getDaysOfMonth(int i) {
switch (i){
case 2:
return isLeapYear(year)?29:28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
//判断闰年的方法
public boolean isLeapYear(int year){
if(year%4 == 0 && year%100 != 0 || year%400 == 0){
return true;
}else {
return false;
}
}
}
public class CalendarTest {
public static void main(String[] args) {
MyCalendar mc = new MyCalendar(1998,7);
mc.show();
}
}