- 面向对象的基本概念
对象:Java程序运行的基本单位
类:同种物体(对象)在属性和行为上的集合与抽象
用来向jvm描述对象的属性和行为
类和对象的关系
描述与被描述的关系(类定义了对象,对象是类的实体)
类并不能规定对象的属性取值,只有具体的对象才能决定属性取值
对象和对象的关系
不同类型的对象,对象可能具有不同的属性和行为
同种类型的对象,也有区别,区别就在同种类型的不同对象,他们的属性取值不同,可以不同
在Java语言的类中,成员变量用来描述对象的属性(也就是事物的属性),成员方法来描述对象的行为(就是事物的行为)
成员方法:只要把我们之前的写的方法中的static修饰符去掉(例如:public void swap(a,b))
定义一个类:class IntValue{}
创建类对象——new,new表达式是堆上的首地址,新的new新的地址
给对象的属性赋值(即给对象的成员变量赋值),通过 对象名.成员变量名 的方式
访问对象的行为——对象名.成员方法
student zs ————zs是一个引用变量,指向堆上的一个值
- 从数据类型的角度认识类和对象
数据类型:一个数据集合和基于这个数据集合的 一组操作
类定义:类体中包括,成员变量和成员方法
类定义中的数据集合:成员变量的集合
类定义的操作集合:成员方法集合
说白了一个类就是一种数据类型的定义
DAY9
注意:同一个包下不能创建同名的类
构造方法
1.方法名和类名相同
2.方法声明中没有返回值这一项
普通就是没有被static修饰的,比如普通成员变量,普通成员方法
- 类加载的内存映像
- 当首次创建某个类的对象的时候,会触发jvm对该类的类加载过程(一个类最多被jvm虚拟机加载一次),将类对应的字节码文件内容加载到方法区内存中存储起来,jvm通过字节码解析认识该类
- 然后在堆上创建对象,根据类的属性在对象内部分配相应的存储空间(对于堆上的东西因为要有值,所以设置为默认初值)
- 将对象的地址复制给引用变量,然后引用变量(对象名)指向了堆上对象
- 通过引用变量找到对象,将我们想要给的初值赋给对象
访问不同对象的相同行为,输出结果不同,随着对象的不同而不同
- 面向对象特殊语法
1.哪些变量是局部变量?方法中定义的变量和方法的形式参数
局部变量 | 成员变量 | |
类中的位置不同 | — | — |
内存中的位置不同 | 存储在方法对应的栈帧中 | 存储在堆上,在对象的内存中 |
初始化值不同 | 没有天生的初始值,必须在使用前用代码初始化局部变量的值 | 堆上的成员变量,天然有默认初始值 |
生命周期不同 | 随着栈帧存在而存在,销毁而销毁 | 随着对象存在而存在,销毁而销毁 |
2.方法引用类型的形式参数
形参和实参的 传递方式是复制传递
引用类型的变量,在调用方法,和被调用方法中,都属于各自方法中定义的局部变量
引用类型的实参和形参的值,在调用方法和被调用方法中各自都有一份
但是,引用类型的实参和形参所指向的数据,是同一份数据
3.构造方法
就是使得jvm在构造对象的时候,帮我我们进行成员变量(以方法参数的形式,接收方法参数,利用接收到的方法参数,来初始化对象成员变量的值)
public Student(String name, int age, boolean isMale, int sno){ }
1.首先在类中定义构造方法语法,有两个不同于一般方法的地方
a.构造方法的方法名固定,和类名相同(确实违反了驼峰命名法)
b.构造方法(没有返回值)的方法声明中,没有返回值这一项
注意事项:
- 一个类中可以定义多个重载的构造方法
- 我们需要知道,当我们没有在类中定义任何一个构造方法的时候,jvm会自动添加一个默认的构造方法(无参构造方法,实际上什么也不会做),但是一旦我们自己在类定义中,定义了哪怕只有一个构造方法,jvm就不会自动帮我们添加那个无参构造方法了
- 构造方法的执行是由jvm来真正调用执行的,在创建对象的最后一步,执行构造方法,给对象的 成员变量赋予coder传递的 初值(在初始化过程中,不能阻止jvm对堆中对象初始化,先jvm赋默认初值,再是赋给构造方法的值)
通过实参列表的对应来解决重载冲突的问题
- 自己定义无参的默认构造方法
//我们需要将student对象默认成员变量取值是 “未知”,-1,true,-1 publ Student(){ name = "未知"; age = -1; isMale = true; sno = -1; System.out.println("hello default constructor"); }
//部分代码未补全,有空在写
//输出结果为 hello default constructor name = 未知,age = -1, isMale = true, sno = -1
//为什么先输出的是hello?
//构造方法执行完之后对象才算真正创建完,创建对象执行的最后一步是执行构造方法,利用构造方法接收到的参数来初始化对象成员变量的值
建议无论用不用到无参构造方法都添加一个,原因在于如果有构造方法,在new 的时候默认构造方法会报错(如果coder不赋予初值)
4.this
- 为了解决方法体中成员变量的隐藏问题
- 方法中定义了和类中同名的成员变量
- 在方法体中,通过同名变量的变量名来访问变量值,我们只能访问到方法中的,那个局部同名变量的值,而访问不到,同名成员变量的值
- 在方法体中,就好像同名成员变量,被同名局部变量给隐藏起来了
this关键字:代表(对象自身)当前对象的引用
当前对象的含义:
a.在构造方法中的this,指代的当前对象,其实就是,构造方法执行时,jvm正在创建的那个对象
b.在普通成员方法的方法体中,this指代的对象对于普通成员方法而言 对象名.方法()
所以对于普通成员方法而言,在哪个对象上调用方法,方法中的this就指的是哪个对象
this关键字的作用:
- 解决成员变量的隐藏问题
- 访问对象的成员(访问当前对象的成员变量值,访问当前对象的成员方法)
- 访问对象的构造方法 this(实参列表)在某个构造方法中,调用其他构造方法
a.this调用构造方法 ,这个代码,只能某个构造方法的方法中
b.this调用构造方法,必须处在构造方法的第一条语句的位置
5.static
static关键字可以修饰成员变量和成员方法
说明:按照严格意义上的面向对象思想,被static修饰成员变量,和static修饰成员方法,都不能算作类中定义的成员
我们习惯上称static修饰的变量为 静态成员变量(简称静态变量),方法为 静态成员方法 (简称静态方法)
- static关键字的特点
1.被当前类的所有对象所共享(判断是否使用static的关键)(只能修饰类)
a.当static修饰了成员变量,该成员变量的值,就不再存储的对象中了,而是单独存储了一份,被类的所有对象所共享
b.当static修饰成员变量方法的时候,该方法被当前类的所有对象共享,当前类对象,方法(和普通成员方法从共享的角度,几乎没有太大区别)
2.可以通过类名访问(对于静态成员,官方推荐 类名. 的形式访问静态变量)
a.可以通过类名直接访问static成员变量的值
b.直接通过类名直接调用static成员方法
一个变量一旦被static修饰,就被当前类的所有对象所共享
3.随着类的加载而加载(首次创建对象时会触发一次类的加载,首次访问一个静态变量或静态方法的时候,也会触发该类的类加载)
a.static成员变量,随着类加载过程,其实就已经在方法区中,分配了内存,并赋予了初值
b.static成员方法,一旦类加载完毕,我们就可以直接访问,static方法,而不必等待,创建对象,然后在对象名,访问方法
4.优先于对象而存在(不依赖于对象而存在)
普通成员的变量离不开对象(原因在于对象的内存在创建对象的时候才分配)
a.从成员变量的角度来理解,static修饰的成员变量,不依赖于对象而存在,因为static修饰的成员变量的值不再储存在该类的每个对象中
b.成员方法角度,被static修饰的成员方法,在没有对象存在的情况下,也可以直接通过类名来调用方法,作为对比,没有被static修饰的普通成员方法,它依赖于对象而存在,原因是普通成员方法中,可以访问普通成员变量的值,而普通对象的值又是依赖于对象而存在的
作为对比,没有被static修饰的成员变量,都依赖与对象而存在,因为他们的值都存储在对象中
注意事项:
1.所谓的在静态上下文无法访问非静态的成员变量,或非静态的成员方法(non-static field ' 变量名' cannnot be reference from a static context)
a.只能是无法访问当前对象的非静态成员变量或当前变量的非静态成员方法(原因在与当前对象可能不存在)
b.但是,在静态方法中,可以访问我们自己new出的对象的非静态的成员变量或成员方法
2.不管是静态方法or非静态方法,方法体中都不能使用static关键字定义变量(了解即可)
静态方法的使用场景:通常是作为工具方法来使用。之所以工具方法被定义为静态方法,是为了方便使用,而工具方法(静态方法)访问的数据都是参数
静态成员变量 | 普通成员变量 | |
所属不同 | 属于类 | 属于对象(所以也称实例变量) |
内存中的位置不同 | 方法区 | 堆内存 |
内存出现时间不同 | 随着类加载而加载,随着类消失而消失 | 随着对象创建而存在,随着对象消失而消失 |
调用不同 | 可以通过类名调用,也可以通过对象调用 | 只能通过对象名调用 |
DAY10
6.代码块
- 在java中,使用{}括起来的代码被称为代码块
- 根据其位置和声明的不同,可以分为局部代码块,构造代码快,静态代码块,同步代码块
局部代码块:
1.声明方式和出现位置:出现在方法体中
2.执行时机:随着方法的执行而执行
优点:限定变量生命周期,及早释放,提高内存利用率(优点理论存在,实际在jvm中效果微乎其微,甚至忽略不计)
我们在开发中,同时还要追求,代码的可维护行(包括代码的可读性)
在嵌套的作用域中(代码块),不能定义同名变量
构造代码块:
1.声明方式和出线位置:{},出线在类中方法体之外
2.执行时机:每次创建对象的时候执行
a.构造代码块和构造方法都是在创建对象的过程中执行的(其中构造代码块先于构造方法执行)
也可以在构造代码块中给成员变量赋初值
b.成员变量的初始化语句和构造代码块,以及构造方法执行顺序的先后关系:
成员变量的初始化语句 vs 构造方法:构造方法后执行
成员变量的初始化语句 vs 构造代码快:执行的先后顺序,依赖于代码书写的先后顺序
构造代码块的使用场景:
1.可以把多个构造方法中相同的提取出来放到构造代码块中,先后顺序为:
每次调用构造都执行,并且在构造方法前执行
2.我们也可以用构造代码快来初始化对象的成员变量的值
静态代码块:static
1.声明方式和出现位置:声明static{},出现的位置:在类中方法体外
2.执行时机:随着类加载而执行,因为同一个类在jvm中,最多只会被加载一次,所以静态代码块最多也只会执行一次
使用场景:最多只需要执行一次的代码(加载数据库驱动)
静态代码块也是静态上下文的一种:静态代码块中无法访问非静态的成员变量和成员方法
但是在非静态的成员方法中,可以访问静态的成员方法和成员变量
7.package关键字
在java源程序文件的第一行使用package声明可以使文件中定义的类成为指定包的成员
(类似于操作系统中的文件目录(组织文件),用来组织类)
注意事项:并非每个java文件都必须有package关键字指定,如果一个java文件中没有packa关键字,属于默认包
当在类体中使用与当前类不同包名的类时,编译器编译时因为无法找到该类的定义而报错
a.使用不同包名的类的全限定名
b.使用import声明,为编译器提供该类的定义信息
8.import注意事项
1.import声明一般紧跟在package声明之后,必须在类声明前,其基本语法如下
import 类的完全限定名
import static test.Teacher.MAX;
2.java语言核心包java.lang包中的类将被隐式的导入,可以直接使用其中的类
3.import声明提供了一种包的智能导入方式:
import<包名>.*;//*--通配符,表示当前包下的所有类
包中的类将根据需要导入,避免使用多条import声明
注意事项:
a.只能导包不能嵌套导入(子包内的类需要重新导入)
b.按需导包
两个包下有同名类,想两个调用,必须有一个是全限定名