目录

1.面向过程和面向对象

1.1面向过程和面向对象概念

1.2面向对象和面向过程的区别

1.3面向对象的专业术语

1.4面向对象的三大特征

2.类和对象的概念

2.1类

2.2类和对象关系

2.3如何定义类

2.4创建对象

3.构造方法

3.1语法

3.2构造方法调用

3.3构造方法的作用

3.4引用为空的时候

3.5实例变量是一个引用,String是引用类型

3.6构造方法调用的传参问题

3.7实例代码块

4.封装

4.1什么是封装

4.2封装的好处?

4.3怎么用?

4.4总结


面向对象是java的核心,贯穿于整个java体系,这个概念会一直伴随我们后面的学习。

1.面向过程和面向对象

1.1面向过程和面向对象概念

面向过程,比较注重步骤,侧重每一步做了什么
1)把冰箱门打开
2)把大象装进去
3)把冰箱门关上
步骤和步骤之间是紧密相连 按顺序进行。具体的每个步骤用函数(方法)来实现

面向对象,注重对象,侧重是谁来做
主体:大象 熊猫  冰箱 
大象{
   走(冰箱){}
}

熊猫{
   走(冰箱){}
}
冰箱{

size;
   打开()
   关闭()
}

1.2面向对象和面向过程的区别

比如我现在不把大象装冰箱了,我想装其他的动物,或者改变冰箱的大小,怎么办呢?

1)把大冰箱门打开
2)把大熊猫装进去
3)把大冰箱门关上


主体:大象 熊猫  冰箱 
大象{
   走(冰箱){}
}

熊猫{
   走(冰箱){}
}
冰箱{

size;
   打开()
   关闭()
}

1)步骤 ,对象
面向过程:耦合度高,扩展性低  (智能手机)
面向对象: 耦合度低,扩展性高   (灯泡、组装电脑)
2)不是对立的,是相辅相成的
对象中的具体方法还是通过方法一步一步实现
所以面向对象只是宏观把控,在微观上还需要面向过程来实现
3)简单问题用的面向过程,复杂问题用面向对象解决

当然这块内容不是一下子就能理解的透透的,这个需要你要通过后期知识积累和项目沉淀来慢慢消化的,这块你听大概就行

1.3面向对象的专业术语

OOD:Object-Oriented Design
OOA:Object-Oriented Analasis
OOP:Object-Oriented Programming

1.4面向对象的三大特征

封装
  继承
  多态

2.类和对象的概念

软件存在的意义就是解决现实世界的问题,所以软件就需要对现实世界进行模拟。现实世界有什么,软件里面就得有什么 。
面向对象编程之所以能成为主流是因为符合人的思维模式。比如我说动物,你脑子是不是会有一个动物的画面,有的人想的老虎,有的人想的是小猫  动物就是类,每个人心里动物的肯定不一样。那在这动物就是一个类,张三脑子想的动物就是对象。
面向对象编程的思想关注的是对象对吧。java中万事万物皆对象,也就是说我们周围的事务都可以看做是对象,比如桌子、电脑、键盘、鼠标等等。那么怎么创建对象?创建对象就必须得现有类,那到底什么是类,什么是对象,类和对象有什么关系呢?

2.1类

类:具有共同特征事务的一种描述,一种抽象的概念,对象:是一个实际存在的个体。
例如:“汽车”就是一个类(所有的汽车都有方向盘、发动机、都能行驶,这是它们的共同特征),“你家的那个汽车”就是一个真实存在的对象。
“人类”就是一个类,一个叫张三 李四的人 这就是对象

类描述事物的共同特征,那么“人”类都有哪些共同特征呢?人类都有姓名、性别、年龄等状态信息(属性),他们还有一个共同的行为就是吃饭(方法)。
类包含:属性+方法,属性描述的是状态是名次,方法描述的是行为动作,动词。

2.2类和对象关系

类和对象关系:类---》创建---》对象(实例)  实例化
对象共同特征----》抽象---》类

但是你有没有发现,当我们把类对应某个具体对象上之后,姓名可以叫张三,是不是也可以叫李四....是。所以我们在访问姓名、性别、年龄的时候,必须先有人这个对象,通过真实存在的人对象去访问他的属性,包括“吃饭”的时候,只有“人”类是不行的,必须先有人类对象,让人类对象去执行“吃饭的”这个动作。

2.3如何定义类

具体我们在java中如何定义一个类呢?
我们得知:类 = 属性 + 方法,而属性描述的是状态,方法描述的是行为动作。行为动作以方法的形式存在,那属性以什么形式存在呢?例如:姓名、性别、年龄,大家想起之前学习的变量了吗?变量用来存储数据。不错,对象的属性以变量形式存在。

package com.example.course.demo01;
/*“人”类:属性+ 方法状态信息(名词):姓名、性别、年龄-----》属性行为动作(动词):吃饭、睡觉  -------------》方法变量分类:方法内/外成员变量:方法外局部变量 :方法内*/
public class Person {//int a;//定义int类型变量,变量名叫a//身份证号//姓名String name;//实例变量,对象级别的,只有有了对象才能去访问//性别(男true   女false)boolean sex;int age;
}

这里所说的变量是我们之前提过的“成员变量当中的实例变量”。为什么叫实例变量呢,实例变量就是对象级别的变量,这样的变量要求必须先存在对象,通过对象才能访问。以上程序当中每个人的no、name、age、sex这些属性都是不一样的,要想访问,必须先创建对象才能访问,不能直接通过类去访问。没有学生对象,谈何学号! 
例如:“中国人”这个类,有一个属性是“身份证号”,每一个中国人的“身份证号”都是不一样的,所以身份证号必须使用一个真实存在的“中国人对象”来访问。不能使用“中国人”这个类去访问身份证号。一个类可以实例化N多个对象,假设通过“中国人”这个类创建了100个“中国人对象”,那么“身份证号”必然会有100个实例变量空间去存储。

2.4创建对象

class Test {public static void main(String[] args) {/*数据类型:基本数据类型(四类八种)引用数据类型:String,class修饰的类型new Person();会再堆中开辟一块内存,然后将内存的地址赋给了pp成为引用* */int a=10;//创建Person对象Person p=new Person();//如何访问对象的内容 引用.属性/*实例变量来说,如果不手动初始化,系统会给你一个默认值* byte short int long   0* double float          0.0* boolean               false* char                  \u0000**/System.out.println(p.name);//nullSystem.out.println(p.sex);//falseSystem.out.println(p.age);//0//给属性赋值p.name="张三";p.age=18;p.sex=true;//输出属性的值System.out.println(p.name);//nullSystem.out.println(p.sex);//falseSystem.out.println(p.age);//0}
}

练习:日期类:包括年,月,日三个成员变量,显示日期的方法
        提供构造方法:定义无参构造方法,和有参构造方法

public class Date {//年int year;////月int month;//日int day;
}
class TestDate{public static void main(String[] args) {//创建Date对象Date d=new Date();
}

3.构造方法

3.1语法

[修饰符列表] 方法名([形参列表]){
          方法体
     }

(1)[]内容不是必须的,目前修饰符列表先默认写成public
     (2)方法名必须和类名保持一致
     (3)构造方法是一种特殊的方法,没有返回值类型的
     (4)形参列表如果不写,就是无参构造
          无参构造和有参构造方法属于方法的重载

3.2构造方法调用

new 构造方法名([实参]);
注:[1]构造方法不写的时候,系统会默认自动给生成无参构造
          如果写了有参构造,系统不会默认生成无参构造
          建议如果你写了有参构造,手动把无参构造也要加上

[2]构造方法虽然没有返回值类型,但它执行结束之后实际上会返回该对象在堆中的内存地址,然后把这个内存地址赋值给了这个变量,这个变量就是“引用”,通过这个引用我们就可以访问这块内存了;这个结果目前可以把它等同看做是对象的内存地址(严格来说不是真实的对象内存地址)

public class Date {//年int year;////月int month;//日int day;//无参构造public Date(){System.out.println("无参构造");}//有参构造public Date(int _year,int _month,int _day){System.out.println("有参构造");year=_year;month=_month;day=_day;}public Date(int _year){System.out.println("有参构造");}public Date(int _year,int _month){System.out.println("有参构造");}
}class TestDate{public static void main(String[] args) {//创建Date对象Date d=new Date();System.out.println(d.year+"-"+d.month+"-"+d.day);Date d1=new Date(2022,11,1);System.out.println(d1.year+"-"+d1.month+"-"+d1.day);}
}

3.3构造方法的作用

日期为什么都是0呢,执行构造方法的时候没有手动给属性赋值,系统会自动赋默认值。实际上我们可以在构造方法中手动给这些属性赋值--》构造方法的作用是专门用来创建对象同时给属性赋值的。

注意:无论手动赋值还是系统默认赋值,都是在执行构造方法的时候赋的值,因为执行了构造方法才会有对象,有了对象才能去访问实例变量

class TestDate{public static void main(String[] args) {//创建Date对象Date d=new Date();d.year=2022;d.month=10;d.day=14;System.out.println(d.year+"-"+d.month+"-"+d.day);Date d1=new Date(2022,11,1);System.out.println(d1.year+"-"+d1.month+"-"+d1.day);//没有对象,哪来的实例变量//System.out.println(Date.year);d1=null;/*Exception in thread "main" java.lang.NullPointerException:Cannot read field "year" because "d2" is null*/System.out.println(d1.year+"-"+d1.month+"-"+d1.day);}
}

注意:实例变量如果没有手动赋值,系统默认赋值---》都是构造方法在执行的时候才会去赋值,它是对象级别的。没有对象,哪来的实例变量。所以实例变量不能通过类名来访问,如System.out.println(Date.year);

3.4引用为空的时候

  d1=null;/*Exception in thread "main" java.lang.NullPointerException:Cannot read field "year" because "d2" is null*/System.out.println(d1.year+"-"+d1.month+"-"+d1.day);

以上程序语法正确,编译通过但是程序在运行阶段当d1 = null执行之后表示“引用d1”不再保存java对象的内存地址,相当于这条线断了就无法找到堆内存,也无法访问这个java对象的内容了,这种情况下就会发生空指针异常。就好比一个小孩儿放风筝,通过拽线来操控风筝,结果线断了,再拽风筝线的时候,已经无法再操控风筝了,这对于小孩儿来说是一种异常。而java程序中把这种异常叫做NullPointerException。


总之,当一个“空的引用”去访问实例变量时一定会发生空指针异常。

3.5实例变量是一个引用,String是引用类型

因为Student对象当中的name这个“属性/实例变量”是一个引用,保存的不是”zhangsan”字符串,而是字符串对象的内存地址。(按照实际来说,字符串”zhangsan”是在方法区的字符串常量池当中,这个后期再继续进行修正)----》接下来,我们再来看看当属性是其他类型引用的时候
Student 加入Date类型的birth属性

package com.example.course.demo03;
/*实例变量是引用数据类型*/
public class Test {public static void main(String[] args) {Person p=new Person();p.name="zhangsn";p.age=18;p.sex=true;//创建Date对象Date d=new Date(2000,1,1);p.birth=d;System.out.println(p.name+p.age+p.sex);System.out.println(p.birth.year+"-"+p.birth.month+"-"+p.birth.day);}
}
class Person {String name;//实例变量,对象级别的,只有有了对象才能去访问//性别(男true   女false)boolean sex;int age;//生日Date birth;//构造方法public Person(){}public Person(String _name){System.out.println("有参");name=_name;}public Person(String _name,boolean _sex,int _age,Date _birth){System.out.println("有参");name=_name;sex=_sex;age=_age;birth=_birth;}
}


总结:对象中实例变量也可以是引用类型。那么当一个对象的属性是引用的时候应该如何访问这个引用所指向的对象呢?这里其实有一个规律,大家记住就行:类当中有什么就可以“.”什么,例如:Vip类中有birth属性,那么就可以v.birth,那么v.birth是Date类型,Date类当中有year属性,那么就可以v.birth.year,你懂了吗?

3.6构造方法调用的传参问题

/*变量传参问题基本数据类型传的是数值,引用数据类型传的是内存地址数值和内存地址都是“值”,所以基本数据类型和引用数据类型都属于“值”传递
*
* */
public class Test01 {public static void main(String[] args) {int a=10;int b=a;//b=10b=20;System.out.println(a);//10Person p1=new Person("张三");Person p2=p1;//p1和p2存的是相同的内存地址,都指向了堆中相同的对象Person p3=new Person("张三三");System.out.println(p2);//内存地址p2.name="李四";System.out.println(p3.name);//张三三}
}
class Person {String name;//实例变量,对象级别的,只有有了对象才能去访问//性别(男true   女false)boolean sex;int age;//生日Date birth;//构造方法public Person(){}public Person(String _name){System.out.println("有参");name=_name;}public Person(String _name,boolean _sex,int _age,Date _birth){System.out.println("有参");name=_name;sex=_sex;age=_age;birth=_birth;}
}

思考下:a赋值给b,a把什么给了b?p1赋值给p2,p1把什么给了p2?
其实a,b,p1,p2就是4个普通的变量,唯一的区别只是a和b都是基本数据类型的变量,p1和p2都是引用数据类型的变量(或者说都是引用),a变量中保存的那个“值”是10,p1变量中保存的那个“值”是0x8888(java对象内存地址),本质上来说10和0x8888都是“值”,只不过一个“值”是整数数字,另一个“值”是java对象的内存地址,大家不要把内存地址特殊化,它也是一个普通的值。
那么“赋值”是什么意思呢,顾名思义,赋值就是把“值”赋上去。a赋值给b,本质上是把a变量中保存的“值10”复制了一份给了b。p1赋值给p2本质上是把p1变量中保存的“值0x8888”复制了一份给了p2。

总结:通过以上内存图我们可以看出“赋值”运算的时候实际上和变量的数据类型无关,无论是基本数据类型还是引用数据类型,赋的都是值。只不过对于引用数据类型来说占两块内存,它赋的这个值是java对象在堆中的内存地址。所以最终会导致两个引用指向同一个堆内存中的java对象,通过任何一个引用去访问堆内存当中的对象,此对象内容都会受到影响。我们来验证一下,让a++,a应该变成了11,但是b不会变,让p1.name = “波利”,然后输出bird2.name的结果肯定也是”波利”

3.7实例代码块

package com.example.course.demo04;
/*
*
* 实例变量和实例方法都是属于对象级别的。
* 实例方法的方法体中可以调用其他的实例方法。
*
* 实例代码块
*    语法结构:{}
* */
public class Dog {{System.out.println("我是实例代码块的内容我,对象级别的");System.out.println("注意:我是构造方法执行之前执行的");}//成员变量中实例变量private String name;private String pinzhong;//无参构造方法public Dog(){System.out.println("无参构造");}//成员方法中的实例方法public String getName(){return name;}public void eat(){System.out.println("吃骨头");shake();}public void haul(){System.out.println("汪汪~");guard();}public  void guard(){System.out.println("看门~");}public void shake(){System.out.println("摇尾巴");haul();}
}

4.封装

4.1什么是封装

封装从字面上来理解就是包装的意思,专业点就是信息隐藏。在现实世界当中我们可以看到很多事物都是封装好的,比如“鼠标”,外部有一个壳,将内部的原件封装起来,至于鼠标内部的细节是什么,我们不需要关心,只需要知道鼠标对外提供了左键、右键、滚动滑轮这三个简单的操作。对于用户来说只要知道左键、右键、滚动滑轮都能完成什么功能就行了。

4.2封装的好处?

--封装可以隐藏内部实现细节,对外只提供了简单的安全的操作入口,所以封装之后,实体更安全了。
--代码来说降低程序的耦合度,提高程序的扩展性,以及重用性或复用性;例如“鼠标”可以在A电脑上使用,也可以在B电脑上使用。

4.3怎么用?

通过案例感受下没有封装,程序会有什么问题。

package com.example.course.demo04;
import com.example.course.demo03.Date;
/*
封装:
1.生活中的封装
(1)鼠标:外壳把里面的组件封装起来了,只暴露左键、右键、滚轮。对于用户来说,鼠标内部怎么工作的,不用关心,只需要知道左键、右键、滚轮
(2)好处:安全:里面的组件你是接触不到扩展性好:在A电脑能用,在B电脑也能用
2.没有封装的案例结论:对类中的属性进行封装,外部程序不能随便访问呢
3.如何封装(1)用private(私有的)修饰属性(2)给外部程序提供访问的接口对属性的访问无非就读和写,所以我们开发两个方法get(读取)/set(写)方法含有static修饰的方法叫静态方法,通过 "类名.方法名()"调用----》类级别没有static修饰的方法叫实例方法,----》对象级别注意 (1)get/set方法是实例方法,是对象级别的(2)get/set方法首字母小写,后面遵循驼峰标志。(3)set可以为属性赋值(构造方法也可以为属性赋值)
* */public class Test {public static void main(String[] args) {Person p=new Person();/*p.age=18;p.age=-18;//与现实不符System.out.println(p.age);*/p.setAge(-18);System.out.println(p.getAge());Dog d=new Dog();d.eat();}
}
class Person {private String name;//性别(男true   女false)private boolean sex;private int age;//生日private Date birth;//get方法//public static 含有public int getAge(){return age;}public void setAge(int _age){if(_age<0||_age>100){System.out.println("年龄必须0~100之间");}else{age=_age;}}public String getName(){return name;}//构造方法public Person(){}public Person(String _name){System.out.println("有参");name=_name;}public Person(String _name, boolean _sex, int _age, Date _birth){System.out.println("有参");name=_name;sex=_sex;age=_age;birth=_birth;}
}

学生类,年龄设置负数--》编译运行都没有问题,但是结构与现实不符。所以外部的程序不能随便访问这个属性,需要对属性进行封装---》加private,报错--》设置完之后  太安全,安全的外部的程序都无法访问了,所以这个时候就需要进入封装的第二步了:对外提供公开的访问入口,让外部程序统一通过这个入口去访问数据就可以了。
对于“一个”属性来说,我们对外应该提供几个访问入口呢?通常情况下我们访问对象的某个属性,不外乎读取(get)和修改(set),所以对外提供的访问入口应该有两个,这两个方法通常被称为set方法和get方法(还记得之前我们接触的方法都是被static修饰的,这些方法直接采用“类名”的方式调用,而不需要创建对象,在这里显然是不行的,set和get方法属于对象级别的,“不同的对象”调用get方法最终得到的数据是不同的,例如zhangsan调用getName()方法得到的名字是zhangsan,lisi调用getName()方法得到的名字是lisi,显然get方法是一个对象级别的方法,不能直接采用“类名”调用,必须先创建对象,再通过“引用”去访问。所以这个方法定义的时候不能使用static关键字修饰,不用static修饰方法我们又叫实例方法。实例方法必须使用“引用”的方式调用。)。

4.4总结

--封装的步骤应该是这样的:需要被保护的属性使用private进行修饰,给这个私有的属性对外提供公开的set和get方法,其中set方法用来修改属性的值,get方法用来读取属性的值。
--set和get方法在命名上也是有规范的,规范中要求set方法名是set + 属性名(属性名首字母大写),get方法名是get + 属性名(属性名首字母大写)。
--其中set方法有一个参数,用来给属性赋值,set方法没有返回值,而get方法不需要参数,返回值类型是该属性所属类型
--先记住,以后讲:另外set方法和get方法都不带static关键字,不带static关键字的方法称为实例方法,这些方法调用的时候需要先创建对象,然后通过“引用”去调用这些方法,实例方法不能直接采用“类名”的方式调用。

有的读者可能会有这样的疑问:构造方法中已经给属性赋值了,为什么还要提供set方法呢?注意了同学们,这是两个完全不同的时刻,构造方法中给属性赋值是在创建对象的时候完成的,当对象创建完毕之后,属性可能还是会被修改的,后期要想修改属性的值,这个时候就必须调用set方法了。

Java零基础-08-面向对象相关推荐

  1. java零基础Ⅰ-- 6.面向对象编程(基础部分)

    java零基础Ⅰ-- 面向对象编程(基础部分) 类与对象 类与对象引出 类与对象概述 快速入门 类与对象的区别和联系 对象在内存中存在形式 属性/成员变量/字段 注意事项和细节说明 如何创建对象 如何 ...

  2. Java编程基础08——面向对象_构造方法静态static

    1.构造方法Constructor概述和格式(掌握) A:构造方法概述和作用 给对象的数据(属性)进行初始化 B:构造方法格式特点 a:方法名与类名相同(大小写也要与类名一致) b:没有返回值类型,连 ...

  3. 马士兵java面向对象_马士兵JAVA零基础后端工程师

    马士兵JAVA零基础后端工程师 简介 Java的应用可以说是无处不在,从桌面办公应用到网络数据库等应用,从PC到嵌入式移动平台,从Java小应用程序(Applet)到架构庞大的J2EE企业级解决方案, ...

  4. java基础入门传智播客 源码_Java-_2020年版Java零基础视频教程(Java 0基础,Java初学入门)魔鬼讲师老杜出品...

    不会闲聊!!!不会扯淡!!!小UP只会分享与Java相关的学习资源 还记得那年带你Java入门的一声"吼"吗? B站目前播放量已经快到450多万播放量的Java零基础教程的创作者& ...

  5. B站百万播放量Java零基础教程视频(适合Java 0基础,Java初学入门),史上最细Java零基础教学视频

    是否还在为学习Java如何入门而烦恼? 是否还在为Java软件如何安装而烦恼? 是否还在找寻着适合零基础的Java视频教程? 动力节点教学总监老杜159集课堂实录Java零基础视频教程,从初学者角度出 ...

  6. 【J2ME 2D 游戏开发系列】◣HIMI游戏开发启蒙教程◢JAVA零基础学习J2ME游戏开发全过程!...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/j2me-2/774.html Himi从写 ...

  7. 一篇文章让你从JAVA零基础入门`OOP`编程12.19

    一篇文章让你从JAVA零基础入门OOP编程 前言: 此文为玄子,复习ACCP-S1课程后,整理的文章,文中对知识点的解释仅为个人理解. 配套PPT,站点源码,等学习资料 一.预科 1.1 JAVA 介 ...

  8. 尚硅谷Java零基础极速入门七天版笔记

    Java零基础极速入门 文章目录 Java零基础极速入门 1 Java快速入门 1.1计算机语言 1.2 Java语言 1.3 JVM 1.4 环境配置 2 基础语法 2.1 变量 2.2 标识符 2 ...

  9. 【Java】Java零基础学习笔记

    文章目录 前言 思维导图 前期准备 卸载JDK 安装JDK Hello,world 可能遇到情况 java程序运行机制 IDEA的安装 java基础部分 基础语法 运算符 包机制 javaDoc文档手 ...

  10. Java零基础入门学习教程(纯干货知识点+视频资源)

    Java 是由 Sun Microsystems 在 1995 年首先发布的编程语言和计算平台.Java 是一项用于开发应用程序的技术,可以让 Web 变得更有意思和更实用. 有许多应用程序和 Web ...

最新文章

  1. 基于OpenCV Haar实战级联分类器的使用
  2. Soft-Actor-Critic-强化学习算法
  3. FPGA设计注意事项
  4. 个人开发—进度记录(一)
  5. 《人性的弱点》--如欲采蜜,勿蹴蜂房。
  6. 数据库mysql菜鸟教程_MySQL数据库菜鸟教程(一)
  7. Vue导出Excel表格信息
  8. 松下plc安装序列号afpsgr7_松下fpwin gr7下载 Control FPWIN GR7(松下plc编程软件) v2.21 中文安装版(附序列号) 下载-脚本之家...
  9. Java合成图片及文字--Graphics2D
  10. MapReduce: 大规模集群上的简化数据处理
  11. springcloud之服务发现笔记
  12. ptp输出内容包含什么_PTP技术及其应用分析
  13. IDEA使用Statistic插件统计代码数量
  14. 如何切换计费模式中的“按需”和“包年包月”?
  15. 在线考试系统总体设计
  16. 在Windows 记事本中快速选中大量文本的方法
  17. ijkplayer源码---音频播放
  18. 记录一次 torch.cuda.is_available()==false的问题解决过程
  19. CANN5.0硬核技术抢先看
  20. Java堆内存Heap与非堆内存Non-Heap

热门文章

  1. 双旦暖心二重礼 | 戴尔官网高效编程电脑OptiPlex拼团立减4100元!
  2. pytorch eq()函数
  3. 网络爬虫ip防止被封常见的三种解决方法
  4. 【win7系统设置wifi热点共享上网教程】
  5. 【RichieZhu】《狙击手:幽灵战士》首部DLC
  6. 其它手机系统改为鸿蒙,现在的安卓手机可以直接更新成鸿蒙系统吗?还是必须购买新的手机?...
  7. [USACO Hol10] 臭气弹 图上期望概率dp 高斯
  8. 逐年缩招,7成毕业生留沪,上交电院近年招生情况如何?
  9. MES管理系统的“五步走”策略,改善车间的管理模式
  10. 自动打卡python脚本_python实现腾讯文档自动打卡教程