1. 面向对象
1.1 传值和传引用
基本数据类型保存值的大小,而数据类型保存内存地址
传值是基本数据类型 传引用是引用类型
局部变量 属于栈帧私有化,栈帧独享
package com.demos;
public class Test02 {
public static void main(String[] args) {
int i = 10;
//m1---->11
//10
//首先执行m1方法 此时输出11,由于是基本数据类型,m1方法执行后i的值不会改变,main输出的i还是为10
m1(i);
System.out.println("main--->"+i);
Animal a = new Animal(18);
System.out.println(a);//com.demos.Animal@15db9742
m2(a);//a a1 地址都相同
System.out.println("main--->"+a.age);//由于 a 是引用类型,因数据改变而改变,a 只是一个地址,指向堆内存,如果堆内存该地址的数据改变,那么指向它地址数据也会改变,而不是改变之前的数据
}
public static void m1(int i) {
i++;
System.out.println("m1---->"+i);
}
public static void m2(Animal a1) {
System.out.println(a1);//com.demos.Animal@15db9742
a1.age++;
System.out.println("m2--->"+a1.age);
}
}
class Animal{
int age;
// Animal(int _age){
// age = _age;
// }
Animal(int age){
//加上this默认使用该参数的值,因此可以不同过变量名解决
//不加上this,始终使用成员变量 age。
//结果为19 19
this.age = age;
//这个结果为1 1
// age = age;
}
}
1.2 区分成员和构造
构造方法 :
[权限修饰符] 类名(参数) {方法体}
作用 : 创建对象,初始化成员属性
方法声明 : [修饰符列表] 返回值类型 方法名(参数) {方法体}
方法名符合命名规则即可 : 字母,下划线,美元符号,数字,不能数字开头,不能使用关键字和保留字,建议望文知义, 驼峰命名法
方法目的 : 代码重用性,提高代码效率
问题:
1 成员方法的方法名可以和类名相同吗?(成员方法可以和构造方法同名吗?)
可以和类名相同
2 如何区分同名的成员方法和构造方法?
看返回值,构造方法木有返回值,成员方法必须有返回值类型,如果没有用void表示.
package com.demos;
public class Test03 {
public static void main(String[] args) {
Test03 a = new Test03();
a.Test03();
}
//构造方法没有放回值类型,连void 都没有
public Test03() {
System.out.println("构造方法");
}
//成员方法有返回值,void也算
public void Test03() {
System.out.println("成员方法");
}
}
1.3 this
1.3.1 是什么?
this是每个对象中,保存自身内存地址的一个引用类型的成员变量
所以说,this就表示对象自己,相当于我们说 “我” 一样
1.3.2 能干什么?
1 在成员/构造方法中,能够区分同名的局部变量和成员变量
2 在构造方法中,也可以用于重载调用当前类中其他的构造方法(必须在第一行)
3 return this 返回当前对象内存地址,可以做到链式调用
1.3.3 怎么用
1.3.3.1 区分局部变量和成员变量
package com.demos01;
public class _01_This {
int i = 1;
public static void main(String[] args) {
_01_This s1 = new _01_This();
s1.i = 19;//对_01_This 成员变量赋值为19
s1.m1();
}
// 1 区分同名的局部变量和成员变量
public void m1() {
// 成员方法中可以直接访问成员变量,因为俩在一起
System.out.println(i);//19
int i = 2;
// 由于和成员变量同名,局部变量优先级高,所以直接访问i是局部变量
System.out.println(i);//2
// 通过对象区分 1 新建对象,访问的i是新建对象的i 并不是当前对象的i
_01_This s = new _01_This();//s 与 s1 的地址不一样
System.out.println(s.i);//s地址指向堆中i的初始值为 1
// 使用当前对象调用,因为s1是main方法中的局部变量,不能访问
// System.out.println(s1.i);
// 使用this调用,因为this就表当前对象(谁调用的这个成员方法,this就是谁)
System.out.println(this.i);//this指向的地址为s1的地址,因为s1,调用了成员方法m1
}
}
class User{
//私有属性 age,只能User 该类访问
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
//构造方法中 区分
public User(int age) {
this.age = age;//age是User有参方法的不是私有的成员变量的age
}
}
1.3.3.2 重载调用构造方法
this重载调用当前类的其他构造方法
必须出现在构造方法第一行
语法 :
this(参数);
package com.demos01;
public class _02_This {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 创建时间对象1
MyDate date1 = new MyDate();
date1.setYear(2021);
date1.setMonth(1);
date1.setDay(13);
// 2021 年 1 月 13 日
date1.println();
// 创建时间对象2
MyDate date2 = new MyDate();
// 0 年 0 月 0 日
date2.println();
// 需求 : 创建时间的时候 必须有日期(需要提供一个有参构造,在创建对象的时候,对三个变量赋值)
MyDate date3 = new MyDate(2021,1,13);
date3.println();
// 需求 : 如果不传入时间,默认时间为 1970年1月1日(创建无参构造,在无参构造中对变量赋值)
MyDate date4 = new MyDate();
// 1970 年 1 月 1 日
date4.println();
}
}
//创建时间类
class MyDate{
private int year;
private int month;
private int day;
// 创建,获取成员变量
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 int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
// 全参构造
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
// 无参构造
public MyDate() {
// this.year = 1970;
// this.month = 1;
// this.day = 1;
// 上面代码,和有参构代码重复,如果是有100行代码呢?就需要再写100行代码
// 重载调用有参构造,必须在有效代码的第一行
this(1970, 1, 1);//里面参数为三个所以地址为三个参数的构造函数地址
}
// 打印
public void println() {
System.out.println(this.year + " 年 " + month + " 月 " + day + " 日 ");
}
}
1.3.3.3 链式调用
链式调用 : xxx.方法().方法().方法()…
核心点 : 前者方法返回值一定是可以调用后者方法的 引用
package com.demos01;
public class _03_This {
public static void main(String[] args) {
_03_This t = new _03_This();
// 成员方法调用应该用对象调用
// 方法在哪个类中,就用哪个类的对象调用
// 所以 t 是_03_This类型
t.m1();
t.m2();
// 链式调用
t.m1().m2();//t调用了m1,则返回的地址为t的地址相当于t.m2()等价
}
public _03_This m1() {
System.out.println("m1执行了");
// 谁调用的这个方法,this就是谁,这里把这个对象地址返回
return this;
}
public void m2() {
System.out.println("m2执行了");
}
}
1.3.4 注意
this 不能出现在静态上下文中
1.4 static
1.4.1 是什么?
static是一个修饰符关键字,用来区别静态和动态属性
1.4.2 能干什么?
static修饰符
1 static修饰的类体中的变量是静态变量
2 static修饰的方法是静态方法
3 static修饰的语句块是静态语句块
1.4.3 怎么用
static修饰符
1、 static修饰的类体中的变量是静态变量
2 、static修饰的方法是静态方法
3 、static修饰的语句块是静态语句块
语法 : static { java代码; }
静态语句块是在类加载阶段执行,并且只执行一次,并且是从上往下执行
静态变量也是在类加载阶段初始化,并且和静态语句块没有优先级之分,从上向下执行初/初始化,所以 不能再静态语句块中 提前使用静态变量,而在方法中是可以的
什么情况下 类加载 : 访问某个类的静态属性的时候,类加载
package com.demos02;
public class _01_Static {
/**
* 打印结果
* 静态语句块1
1
静态语句块2
main------------>
static 是属于类级别的,程序运行时会进行类加载,这个加载比main方法要早,加载到静态区
所以先执行静态语句块 执行一次就结束!。
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("main------------>");
}
static {
// 报错,说明 静态语句块和静态变量都是在类加载阶段初始化的,初始化优先级一致
// 从上往下初始化,所以 执行该代码段的时候,变量i还没有被初始化,所以报错
//Cannot reference a field before it is defined
// System.out.println(i);
System.out.println("静态语句块1");
}
public static void m2() {
// 因为方法不调用不执行
// 而调用执行只能在执行阶段才可以,而静态变量是在加载阶段
// 所以 能够保证 在执行m2方法的时候,变量i一定是存在的,所以 可以再变量声明之前使用
System.out.println(i);
}
// 静态变量
static int i = 1;
// 静态方法
public static void m1() {
System.out.println(i);
}
// 静态语句块/静态代码段
static {
System.out.println(i);
System.out.println("静态语句块2");
}
}
1.4.4 实例语句块
实例语句块
语法 : {
java代码;
}
实例语句块等同于成员方法,只是没有名字
执行顺序 : 静态语句块 > main方法 > 实例语句块(需要new对象 才会执行)
package com.demos02;
/**
* 执行结果:
* 静态语句块1
静态语句块2
main
实例语句块1com.demos02._02_Static@15db9742
实例语句块2
构造方法
实例语句块1com.demos02._02_Static@6d06d69c
实例语句块2
构造方法
*
* 静态语句块属于类加载阶段,先执行静态语句块
* 再执行main
* main中有两个实例化对象,都是_02_Static()每次实例化对象地址不同,开辟新的空间地址。依次运行完实例化后的实例语句块
*
*
*
*
* */
public class _02_Static {
// 实例语句块
{
System.out.println("实例语句块1"+this);
}
{
System.out.println("实例语句块2");
}
// 静态语句块
static {
System.out.println("静态语句块1");
}
static {
System.out.println("静态语句块2");
}
public static void main(String[] args) {
System.out.println("main");
// 如果不实例化 实例语句块不执行,并且实例化几次,就执行几次
new _02_Static();
new _02_Static();
}
// 构造方法
_02_Static(){
System.out.println("构造方法");
}
}
1.4.5 静态调用
静态调用,使用类名调用
那么可以使用对象调用吗? 可以
package com.demos02;
/** 静态方法m1
成员方法m1
静态方法m1
静态方法m1
*
*
* 简单理解 static 数据一眼 地址没有发生变化jvm自动把对象引用变量改成类名所以地址都是一样的,
* 成员可以一样可以不一样,实例化对象后,地址都会不一样
*
*/
public class _03_Static {
public static void main(String[] args) {
_03_Static.m_2();
// 不能使用类名调用成员属性
// _03_Static.m_1();
_03_Static s = new _03_Static();
s.m_1();
// 静态方法也可以使用对象调用,因为在编译阶段,就会把对象引用变量转换为对应的类名去调用
s.m_2();
s = null;
// 空指针异常
// s.m_1();
//
// 可以调用,默认把s转化成_03_Static
s.m_2();
}
public void m_1() {
System.out.println("成员方法m1");
}
public static void m_2() {
System.out.println("静态方法m1");
}
}
1.4.6 静态和成员的区别以及应用场景
变量分类 :
静态变量 : 类中使用static修饰
成员变量 : 类中非static修饰
局部变量 : 方法中声明的变量是局部变量,作用域让当前方法使用
初始化时机 :
静态变量 : 类加载阶段初始化
成员变量 : 创建对象的时候初始化(构造方法)
应用场景 :
静态变量 : 类级别的,是所有对象共享的,比如一个静态变量 age = 18 ,那么说明所有对象都有这个age属性,并且值都是18
所有对象共有的属性和值
成员变量 : 对象和对象之间有相同的属性,但是可能有不同的值,非对象共享
package com.demos02;
public class _04_Static {
public static void main(String[] args) {
Student s1 = new Student(18, "张三");
Student s2 = new Student(18, "李四");
System.out.println(s1.age+" : "+s1.name);//18 : 张三
System.out.println(s2.age+" : "+s2.name);//18 : 李四
Student.addr="石家庄";
System.out.println(Student.addr);//石家庄
// 静态是对象共享数据,即使使用对象去访问,编译时也会转换为类名去访问
s1.addr="河北";//static 引用地址相同
System.out.println(s1.addr);//河北
System.out.println(s2.addr);//河北
s1.age = 19;//地址不同
System.out.println(s1.age);//19
System.out.println(s2.age);//18
}
}
class Student{
int age;
String name;
static String addr;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
}
1.5 封装
封装是把对象的所有组成部分组合在一起,封装使用访问控制符将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。
作用
适当的封装可以让代码更容易理解和维护,也加强了代码的安全性。
1.5.1 软件包机制
1.5.1.1 package
目标 : 当前文件的编译和运行
软件包机制 :
1 为了解决类的命名冲突问题
2 在java中使用package语句定义包
3 package语句只能出现在java源文件中的第一行
4 包命名通常采用公司域名倒叙
5 package限制的是class文件的放置位置(编译之后,把class文件放到哪里去)
com.tledu.oa.system
以上包命名可以体现出来 : 这个项目是天亮教育开发的OA项目,当前处于OA项目中的system模块
6 完整的类名 是带有包名的
7 带有包名的文件,编译应该是这样
javac -d 生成路径 java源文件路径
javac -d ./ -encoding utf-8 _01_Package.java
8 运行
java 包名.类名
什么是文件名 : 能够找到这个文件的全路径
import
package com.demos03;
public class _01_Package {
public static void main(String[] args) {
// 使用当前包下的类的时候,可以直接写类名也能找到
A.m1();
// 使用非当前包下的类中属性的时候,必须写类全名(包名.类名) 才能找到
com.demos03.com.B.m1();
}
}
package com.demos03;
import java.util.Date;
import com.demos03.com.*;
//导入静态属性 需要加static
import static com.demos03.com.C.*;
import static com.demos03.com.B.age;
public class _02_Package {
public static void main(String[] args) {
B.m1();
C.m1();
Date date = new Date();
System.out.println(date);
// 调用其他类中的静态属性的时候,必须要加类名
System.out.println(B.age);
// import static com.demos03.com.B.age; 导入静态属性后 可以直接使用
System.out.println(age);
//import static com.demos03.com.C.*
m1();
}
}
导入该类中所有的静态属性(静态变量/静态方法),让当前类可以不加前缀,直接调用
import static com.demos03.com.C.*;
import :
1 引入其他需要的类
2 只能出现在package语句执行,class语句之上
3 java核心类不需要导入,可以直接用,其他都不行
java.lang
语法 :
import 包名.类名; 导入单个类
import 包名.; 导入该包下所有的类
注意 : eclipse编程过程中,按空格的时候 会自动导包,如果程序没问题,但是报错,可以查看是不是包导错了
导入该类中所有的静态属性(静态变量/静态方法),让当前类可以不加前缀,直接调用
import static com.demos03.com.B.age;
不建议这样使用,在当前类中,不容看出来,这个变量是谁的变量
1.5.2 权限修饰符
private 私有化权限修饰符 ,除了自己(当前类)之外,都不能访问
public 公共的权限修饰符 , 谁都能访问
不写权限修饰符的时候 : 要么当前类中使用,要么当前包中使用
protected 受保护的权限修饰符 , 要么同类,要么同包,要么有继承关系