主线:1.以人为本(程序的思维接近于人的思维) 2.如何实现代码的复用
1:) 机器语言(1.0组成): 可读性极差, 把人想象成机器(硬件), 没有什么代码复用
2:)汇编语言(简单英文替换1.0指令): 可读性好一些, 开发人员需要懂硬件, 没有什么代码复用
面向过程编程语言: 例如C语言, 重点在于过程(步骤), 在细节,函数 对数据关注不是很高 代码的重用层次: 函数级
面向对象编程语言: 例如java, C#,python… 重点在整体, 在对象上, 这个对象包含什么数据?包含的动作(函数/方法)? 代码的重用层次: 类层次/对象层次
生活中的实体,看得见摸得着的事物都可以看作是对象
一组相同特征的对象的集合,是对对象抽象的描述
对象是类的实例化(具体化),类是对象抽象出来的,以类为模板创建对象,使用的是对象而不是类。
public 缺省(默认default) protected private 一般使用public
1:)属性是定义在类的大括号中的,变量定义在方法中
2:)属性在整个类中有效,变量只在定义它的方法内部有效
3:)属性有初始值,根据数据类型确定;而变量没有初始值,直接使用时会报错
byte/short/int/long: 0
float/double: 0.0
boolean: false
char: \u000(表示为空)
String ,其他的类类型: null
类名 对象名 = new 类名();
对象. 属性/方法
包含main方法的类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIJPbrem-1658545391530)(D:\飞思实训三\课件\笔记\7-19笔记\assets\image-20220719152837645.png)]
Person p1 = new Person()
; p1是保存在栈中,而且保存的是new Person在堆中的一个地址码,而new Person()是保存在堆中.名词性描述(方法:动词性描述)
概念:方法是对象的动态的描述, 表示这个对象拥有什么行为或者什么功能,方法是具有独立功能的代码块,不调用就不执行。
作用:提高代码的复用性
类中的方法 不调用不执行
1:)在同一个类中时: 方法名();
public class Student {
public void a(){
System.out.println("a方法执行>>>");
}
public void b(){
a();//b()方法调用a()方法,只需要直接写a();不需要创建Student类的对象,因为他们都是属于Student类的方法,所以不需要去创建Student类的对象
}
}
2:)不同类之间调用方法时 : 对象名. 方法名(); 也就是说,当你需要在一个类中调用另一个类的方法,就必须先创建对象,通过对象来调用方法
Student类:
public class Student {
public void a(){
System.out.println("a方法执行>>>");
}
}
Teacher类:
public class Teacher {
//Teacher类的b()方法调用Student类的a()方法
public void b(){
//1.创建Student类的对象
Student stu = new Student();
//2.通过对象名.方法名()调用Student类的a()方法
stu.a();
}
}
方法不能嵌套,即方法内部不能定义方法,也不能定义属性(但是可以调用方法,可以定义局部变量)
public void fun1(){
//方法内部定义一个方法, 错误
/*public void fun2(){
}*/
//方法内部定义一个属性, 错误
//public int a;
//定义局部变量 可以
int a;
}
方法的返回值类型为void,表示该方法没有返回值,没有返回值的方法可以省略return语句不写,如果要编写return,后面不能跟具体的数据;如果是其他的返回类型,必须要用return返回结果。
break: 结束循环,只能在switch,循环中使用,
return: 结束方法(可替换break)
return 结果:先返回结果,再结束方法
1:)当返回值为void时,用 return 结果 返回,会报错
2:)return 后面返回多个结果 return 结果1,结果2 ,报错、
//第一种解决方案: 返回值类型变成数组类型
public double[] fun3(){
double height = 1.75;
double weight = 70;
double[] rs = new double[2];
rs[0] = height;
rs[1] = weight;
return rs;
}
//第二种解决方案: 把多个数据封装成一个对象,数据作为这个对象的属性
//返回的是类的对象
public Person fun4(){
double height = 1.75;
double weight = 70;
String name = "张三";
Person person = new Person();
person.height = height;
person.weight = weight;
person.name = name;
return person;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JkZMzy59-1658545391531)(D:\飞思实训三\博客\我的\java面向对象\assets\image-20220720144042170.png)]
当一个方法需要根据不同的情境输入不同类型的参数时,不需要再额外定义一个具有相同功能而参数列表类型不同的方法。例如我们要使两个数相加,可以定义一个add(int a, int b)方法,此时由于这个方法不能传入double等其他类型的数据,我们可以使用方法重载,即add(double a,double b)等,方法的重载可以让调用者不需要记住一堆方法名, 只需要记住一个方法名就够了
public class Calculator {
public int add(int a , int b){
return a+b;
}
public double add(double a , int b){
return a+b;
}
public double add( int a ,double b){
return a+b;
}
private void add(){
System.out.println(1+2);
}
}//以上都是方法重载
当我们创建对象时其实new 类名()就是一个构造方法。如果没有在类中手写构造方法,Java虚拟机会创建一个空的构造方法,格式为
public 类名(){}
如果已经在类中写了构造方法,则Java虚拟机不会创建构造方法了,每创建一个对象,都会自动调用一次构造方法
idea 自动生成构造方法: alt + insert键
构造方法名与类名相同
构造方法没有返回值这一说法
构造方法不能在方法中用return 语句返回一个值
[访问修饰符] 类名(参数列表){
//方法体
}
通过new关键字调用, new 构造方法();返回创建的类的对象
类的构造方法可以为类的所有实例对象的成员变量进行初始化操作,当一个类的实例对象刚产生时,也就是当我们new一个实例对象时,构造方法会自动被调用,可以在该方法中写入要完成的初始化操作。构造方法还可以创建对象
这是因为构造方法由Java编译器负责调用,而编译器必须知道哪一个才是构造方法,采用与类同名的方式应该是最简单合理的。
和一般的方法重载一样,它们具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用new 关键字创建对象时,该调用哪个构造方法了。Java 会根据我们在括号中传递的参数,自动为我们选择相应的构造方法。Person p = new Person(参数列表),根据参数列表的不同去调用不同的构造方法。重载构造方法可以完成不同初始化的操作。
1:) 在Java的每个类里都至少有一个构造方法,如果程序员没有在一个类里定义构造方法,系统会自动为这个类产生一个默认的构造方法,这个默认构造方法没有参数,在其方法体中也没有任何代码,即什么也不做。一旦编程者为该类定义了构造方法,系统就不再提供默认的构造方法了。
2:)如果程序员定义的构造方法是有参数的,那创建对象时就必须传参,否则会报错。针对这种情况,我们只要自己定义构造方法时,都需要再带上一个无参数的构造方法,否则,就会经常碰到上面这样的错误。
3:)如果局部变量的名字与属性名一样,则采用就近原则
public Student(String name, String sex){
name = name;//此时相当于把局部变量的值赋值给了局部变量,对象的name属性没有拿到值
this.sex = sex;//如果局部变量的名字与属性名一样,可以用this.属性名 来区分属性和布局变量
}
代表本类的一个对象,谁调用就是谁
(1)this. 属性名 调用本类中的属性,也就是类中的成员变量,区分局部变量与属性;(this相当于是对象的名字)
(2)this调用本类中的其他方法,一般省略this, (方法都在同一个类中,可以直接调用);
(3)this调用本类中的其他构造方法,调用时要放在构造方法的首行。
public class Student {
String name; // 定义一个成员变量name
public void setName(String name) { // 定义一个参数(局部变量)name
//这个this一定不能省略
this.name = name; // 将局部变量的值传递给成员变量
}
public void fun(){
//这个this可以省略,可以写成 setName(“张三”); 同类中的方法调用
this.setName("张三"); //调用setName()的方法
}
}
1:)只是方法的调用,不会创建对象(不要在构造方法里使用new 类名()来调用其他的构造方法!会再创建出对象)
2:)只能在构造方法中使用,且必须在第一行
public class Student {
public Student() { // 定义一个构造方法
this("Hello");// 通过this()来调用另一个Student(String name)构造方法
System.out.println("构造方法执行了");
}
public Student(String name) { // 定义一个带形式参数的构造方法
}
}
static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。
只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。
static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,**可以直接通过类名来访问,**访问语法为:
类名.静态方法名(参数列表…)
类名.静态变量名
用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大)。
类成员变量分为两种,被static修饰的变量,叫静态变量或类变量;没有被static修饰的变量,叫实例变量
静态变量在内存中只有一个拷贝(节省内存),Java虚拟机(JVM)只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),也可以通过对象来访问(但是这是不推荐的)。
对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。所以一般在需要实现以下两个功能时使用静态变量:
1).在对象之间共享值时(作为常量)
2).方便访问变量时
public class TestStatic1 {
int a; //a 是属性,是对象的成员变量,每一个对象都会有自己的属性
static int b; //这个是类变量,所有的该类的对象都共享它
public static void main(String[] args) {
//创建本类的一个对象
TestStatic1 t1 = new TestStatic1();
t1.a = 10; //给属性赋值
t1.b = 20;//给类变量赋值,也可以写成: TestStatic1.b=20;
//创建本类的另外一个对象
TestStatic1 t2 = new TestStatic1();
t2.a = 5;
t2.b = 8;
System.out.println("t1对象:t1.a="+t1.a);//10
System.out.println("t1对象:t1.b="+t1.b);//8
System.out.println("t2对象:t2.a="+t2.a);//5
System.out.println("t2对象:t2.b="+t2.b);//8
}
}
静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员方法),只能访问所属类的静态成员变量和成员方法。
public class TestStatic2 {
int a;
static int b;
public static void fun1(){
System.out.println("这是TestStatic2类的静态方法fun1");
}
public static void fun2(){
// a=10;// 不能直接访问a,因为static修饰的方法只能直接访问本类的静态的成员变量
//fun3();//报错,不能直接访问fun3,因为static修饰的方法只能直接访问本类的静态方法
b=10;//可以访问,因为b是静态的
fun1();//可以访问
System.out.println("这是TestStatic2类的静态方法fun2");
}
public void fun3(){
System.out.println("这是TestStatic2类的非静态方法fun3");
}
}
public class TestStatic3 {
public static void main(String[] args) {
//访问TestStatic2总的fun2方法,只需要使用类名.fun2()
//因为fun2是静态方法
TestStatic2.fun2();
//调用TestStatic2非静态方法,只能使用对象名.方法名()来调用
System.out.println("====================");
TestStatic2 t1 = new TestStatic2();
t1.fun3();
}
}
对象.静态属性(方法)
类名:静态属性(方法) 推荐使用这个
工具类、静态代码块
(不要随便定义静态资源)
1.静态资源只能使用静态资源(例如静态方法里只能使用静态变量、调用静态方法)
非静态方法的调用, 在其他类,main方法内调用: 先创建方法所在类对象,然后通过对象名.方法名() 来调用
静态方法的调用: 在其他类,main方法内调用, 直接使用类名.静态方法名()
静态方法优点: 调用简单
静态方法的缺点: 无法使用非静态资源(实例属性,非静态方法, this,super),只能使用静态资源, 非静态方法调用非静态资源,也调用静态资源
静态方法的缺点2: static修饰的, 不会被gc回收, 等到程序结束之后才回收
在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。
静态方法不能以任何方式引用this和super关键字(super 关键字在下一章讲解)。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。
main()方法是静态的,因此JVM 在执行main 方法时不创建main 方法所在的类的实例对象,因而在main()方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在以后的例子中会多次碰到。
一个类中可以使用不包含在任何方法体中的静态代码块(static block ),当类被载入内存时,所有的静态代码块被自动执行,且只被执行一次,且在构造方法之前执行,静态块经常用来进行类属性的初始化,一个类可以写多个静态代码块, 执行顺序,从上往下。如下面的程序代码:
语法:
ststic{
//静态代码块
}
public class TestStatic4 {
//定义一个静态代码块
static{
System.out.println("这是一个静态代码块");
}
//构造方法
public TestStatic4(){
System.out.println("这是构造方法");
}
public static void main(String[] args) {
TestStatic4 t1 = new TestStatic4();
TestStatic4 t2 = new TestStatic4();
}
}
//结果
这是一个静态方法
这是构造方法
这是构造方法
在Java中使用包来对类进行分类 ,在文件系统就是一个文件夹
一般是公司域名的反写 例如百度域名:www.baidu.com 百度项目的包名:com.baidu.[项目名].[模块名]
不能以关键字命名,否则会变成普通文件夹(图标有圆点的是包,没有就是普通文件夹)
1:)当一个类想要使用另一个类,如果这两个类在同一个包中,可以直接使用,不需要导包
2:)如果想要使用的类位于java.lang包中, JVM虚拟机会自动导入(例如String、System 等等
如果两个类不在同一个包中,且被使用的类也不属于java.lang包,则需要用import关键字导入,且位于class外面
import 包名.类名//语法
import java.utils.Scanner;//导入java.utils包中的Scanner类
import java.utils.*;//导入java.utils包中所有的类
静态导入, 把某个类的所有的静态方法导入‘
封装是 JAVA 面向对象的特点的表现,封装是一种信息隐蔽技术。它有两个含义:即把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位;以及尽可能隐藏对象的内部结构。也就是说,如果我们使用了封装技术的话,别人就只能用我们做出来的东西而看不见我们做的这个东西的内部结构了。提高了安全性和复用性
1:)把属性的访问修饰符设置为private(修饰的资源只能在本类中使用)
2:)给属性提供public 的get/set方法 IDEA快速生成 alt+insert
例如限制用户的年龄只能在16-40岁,可以将age属性设置为private,在setAge(int age)方法中放入限制age的逻辑代码(例如if语句)
- public: 该成员外部可见,即该成员为接口的一部分
- private: 该成员外部不可见,只能用于内部使用,无法从外部访问。
- protected:后面介绍
Person类:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void showInfo(){
this.setName("无名氏");
age = 21;
}
}
TestPerson类:
public class TestPerson1 {
public static void main(String[] args) {
Person p1 = new Person();
//p1.setName()可以访问,因为setName是public
p1.setName("张三");
//p1.age不能访问,因为age是private的
//p1.age=21; System.out.println(p1.getName());
}
}
程序分析:
一个类的内部方法并不受封装的影响。Person的内部方法showInfo()可以调用任意成员,即使是设置为private的age. 外部方法只能调用public成员。当我们在Person外部时,比如TestPerson类中,我们只能调用Person类中规定为public的成员,而不能调用规定为private的成员。
通过封装,Person类就只保留了下面几个方法作为被其他类调用.
- getName()
- setName()
- getAge()
- setAge()
- showInfo()
如果我们从TestPerson类的main中强行调用age:p1.age=21将会报错
1:)提高易用性(使用简单),编写一个类,内部很复杂,将复杂的代码封装起来(例如用private修饰),暴露出几个方法。
2:)提高安全性,将某些方法和属性屏蔽起来,禁止用户访问,从而提高类的安全性(保护数据)
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例和方法,或子类从父类继承方法,使得子类具有父类相同的行为。父类更通用,子类更具体,子类会具有父类的一般特性也会具有自身的特性。注意:构造方法不能继承,且子类不能访问继承的private资源
1:)实现代码的重用, 基于类层次的代码重用
2:) 把多个子类中公共的代码,抽取出来, 放到父类中, 子类继承父类, 这个公共代码,被子类继承,从而实现代码的重用
1:)把子类公共的代码抽取出来,形成父类
2:)使用关键字extends让子类继承父类
class 子类 extends 父类 { }
注意:
在 java 中只允许单继承,而不允许多重继承,也就是说一个子类只能有一 个父类,但是 java 中却允许多层继承. 比如类 B 继承了类 A,而类 C 又继承了类 B,也就是说 类 B 是类 A 的子类,而类 C 则是类 A 的孙子类。我们java的所有类都有一个祖先类,就是我们的Object类.如果一个类没有显示写继承哪个类,默认继承java.lang.Object
在创建一个子类的对象时会默认先去调用父类中的无参构造方法,之后再 调用本类中的相应构造方法。
public 子类(){
super();//默认调用父类中的无参构造方法,默认省略
super(参数列表);//调用父类中的有参构造方法,此时不会执行父类中的无参构造方法
}
1:)第一步是先初始化父类的属性**(面试题)**
2:)调用父类的构造方法
3:) 初始化子类的属性
4:)执行子类的构造方法
super表示的是父类的对象,this表示的是本类的对象
注意:
用 super 调用父类中的构造方法,只能放在程序的第一行。
super 关键字不仅可以调用父类中的构造方法,也可以调用父类中的属性或方法,
super.父类中的属性 ; 一般不这样使用,因为属性一般用private修饰(属性私有化)
super.父类中的方法() ;
super([参数]):调用父类的构造方法
this([参数]):调用本类的构造方法
1:)只能在子类的构造方法中调用且必须在第一行(所以super()与this()不能同时存在,因为他俩都要在构造方法的首行)
2:)如果子类构造方法没有写super(), jvm会自动添加super(), 手动编写super()调用父类构造方法, jvm不会添加`super()
总结:
- 子类拥有父类非private的属性,方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。
Java面向对象的基本思想之一是封装细节并且公开接口。Java语言采用访问控制修饰符来控制类及类的方法和变量的访问权限,从而向使用者暴露接口,但隐藏实现细节。访问控制分为四种级别:
(1)public
: 用public修饰的类、类属变量及方法,包内及包外的任何类(包括子类和普通类)均可以访问,(同项目下的类都可以访问);
(2)protected
: 用protected修饰的类、类属变量及方法,包内的任何类及包外那些继承了该类的子类才能访问,protected重点突出继承(同一个包或者继承的子包可以访问);
(3)default
: 如果一个类、类属变量及方法没有用任何修饰符(即没有用public、protected及private中任何一种修饰),则其访问权限为default(默认访问权限)。默认访问权限的类、类属变量及方法,包内的任何类(包括继承了此类的子类)都可以访问它,而对于包外的任何类都不能访问它(包括包外继承了此类的子类)。default重点突出包;
(4)private
: 用private修饰的类、类属变量及方法,只有本类可以访问,而包内包外的任何类均不能访问它。
访问级别 | 访问控制修饰符 | 同类 | 同包不同子类 | 同包子类 | 不同包不是子类 | 不同包子类 |
---|---|---|---|---|---|---|
公开 | public | √ | √ | √ | √ | √ |
受保护 | protected | √ | √ | √ | √ | |
默认 | 没有访问控制修饰符 | √ | √ | √ | zee | |
私有 | private | √ |
注意:
protected修饰符的修饰的成员变量和方法也称为受保护的成员变量和方法, 受保护的成员变量和方法可以在本类或同一个包中的其它类(包括子类)中通过类的实例进行访问,也可以被同一个包中的类或不同包中的类继承,但是不能在不同包中的其它类(包括子类)中通过类的实例进行访问。
子类继承了父类,那么子类的对象理应可以使用父类中的非private方法,如果子类想实现与父类不一样的效果怎么办呢?此时子类可以重写父类中的方法,当子类的对象再调用这个方法时,就不再是执行父类中写的那个了,而是执行在子类中重写的那个方法,**即保持方法的定义不变,但方法内部实现同父类中不同,**很好理解:如果子类重写了父类中的方法,调用的就是子类中的实现,否则就调用父类中的方法
1:)子类重写父类或父辈类中的方法,父类方法的参数列表必须完全与被子类重写的方法的参数列表相同
2:)父类的返回类型必须与被子类重写的方法返回类型相同,
3:) Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限
public void showInfo(){
super.showInfo();//调用父类那个被重写的方法
System.out.print("子类重写父类的方法")
}
快捷键 alt+insert ctrl+o
如果父类中的某个方法,对于他的不同子类来说有着不一样的实现效果,(也就是说,父类不用实现这个方法,这个方法交给不同的子类自己去重写),此时父类的这个方法不用去写方法的实现,只需要声明这个方法让子类去继承就 可以了,但是如果这样,程序会编程出错,所以就得加一个关键字: abstract, 这种只需要声明,不需要实现方法体的方法,我们叫做抽象方法.但是如果一个类中包含了抽象方法,那么该类也必须声明为抽象类,也就是说:含有抽象方法的类叫做抽象类, 声明这个类时也需要加adstract关键字.
1:)访问修饰符不能是private
2:)抽象方法不能使用static、final修饰**
final意为“最终的”,在 Java 中声明类、属性和方法时,可使用关键字 final 来修饰。
1、 final 标记的类不能被继承。
2、 final 标记的方法不能被子类复写。
3、 final 标记的变量(成员变量或局部变量)即为常量,只能赋值一次,而且只能在声明的时候就赋值。
final int a;//报错
final int a = 0;//只能赋值一次,不能修改值,值相同也不行,
public void fun(){
a = 0;//报错,值相同也不能赋值,只能赋值一次
}
通过一个父类引用不同的子类
抽象类也可以像普通类一样,有构造方法、一般方法、属性,更重要的是还可以有一些抽象方法,留给子类去实现.
1:)访问修饰符不能是private
2:)抽象方法不能使用static、final修饰**
final意为“最终的”,在 Java 中声明类、属性和方法时,可使用关键字 final 来修饰。
1、 final 标记的类不能被继承。
2、 final 标记的方法不能被子类复写。
3、 final 标记的变量(成员变量或局部变量)即为常量,只能赋值一次,而且只能在声明的时候就赋值。
final int a;//报错
final int a = 0;//只能赋值一次,不能修改值,值相同也不行,
public void fun(){
a = 0;//报错,值相同也不能赋值,只能赋值一次
}
通过一个父类引用不同的子类
当新建一个子类时,只需要该子类继承父类,并且实现父类中的抽象方法即可而不需要去修改别的类