文章目录
JAVASE 【Java基础五之面向对象2】
1、封装
1.1含义
将对象中数据或代码逻辑隐藏起来。对数据的操作在类的内部完成,对外界隐藏实现的细节。
1.2好处
- 对象(或组件)内部代码实现的细节可以对外隐藏。
- 简化外部使用对象时的操作难度。外部使用对象时,调用对象暴露出来的方法即可。
- 让整个系统的开发组件化、模块化程度更高,更有利于实现:高内聚、低耦合。
1.3示例
public class MarryObject {
// 将属性的权限修饰符设置为私有,不允许外部直接访问
private int age;
// 对外暴露的获取数据的getXxx()方法
public int getAge() {
return age;
}
// 对外暴露的设置数据的setXxx()方法
public void setAge(int ageOutter) {
// 在方法内部,根据内部的逻辑,对外界数据进行修正
if (ageOutter < 20) {
age = 20;
} else if (ageOutter > 60) {
age = 60;
} else {
age = ageOutter;
}
}
}
2、构造器
注意:构造器和方法是两码事,各是各的。
- 2.1构造器引入
当我们使用new关键字创建一个类的对象时,就是在使用这个类的构造器了:
如果我们没有明确声明构造器,那么系统回给类分配一个隐式的构造器。
2.2构造器的作用
- 作用1:创建对象。
- 作用2:在创建对象的过程中,对类进行初始化操作。这些操作写在构造器的大括号中。
- 初始化操作放到构造器里面,由构造器自动完成,程序员就不必在创建对象后还想着对这对象做初始化操作。
2.3构造器的组成部分
2.4构造器的参数
[1]有一个参数构造器例子
public class Soldier {
private String soldierName;
public Soldier(String soldierName) {
this.soldierName = soldierName;
}
}
注意:当类中声明了有参构造器之后,系统将不再给这个类分配无参的构造器。
[2]一个类可以有多个构造器
根据参数列表不同,多个构造器之间是重载关系。规则和方法重载一致:
- 要么参数个数不同
- 要么参数类型不同
public class Soldier {
private int age;
private String soldierName;
private String weapon;
private String gender;
public Soldier() {
}
public Soldier(int age) {
this.age = age;
}
public Soldier(String soldierName) {
this.soldierName = soldierName;
}
public Soldier(String soldierName, String weapon) {
this.soldierName = soldierName;
this.weapon = weapon;
}
public Soldier(String soldierName, String weapon, String gender) {
this.soldierName = soldierName;
this.weapon = weapon;
this.gender = gender;
}
public Soldier(int age, String soldierName, String weapon, String gender) {
this.gender = gender;
this.weapon = weapon;
this.soldierName = soldierName;
this.age = age;
}
}
2.5构造器相关语法规则
- Java语言中,每个类都至少有一个构造器
- 默认构造器的修饰符与所属类的修饰符一致
- 一旦显式定义了构造器,则系统不再提供默认构造器
- 一个类可以创建多个重载的构造器
- 父类的构造器不可被子类继承
3、this关键字
- 3.1含义
-
类的方法中:代表调用当前方法的对象
-
类的构造器中:代表当前构造器正在创建的对象
- 3.2this能干什么
[1]调用属性
System.out.println("我的年龄:" + this.age);
System.out.println("我的姓名:" + this.soldierName);
System.out.println("我的武器:" + this.weapon);
[2]调用方法
System.out.println("我的性别:" + this.getGender());
[3]调用构造器
在类中的某个构造器中调用这个类的其他构造器:
public class Tiger {
private String tigerName;
private int tigerAge;
public Tiger() {
System.out.println("这里是Tiger类的无参构造器");
}
public Tiger(String tigerName) {
this();
this.tigerName = tigerName;
System.out.println("这里是Tiger类的一参构造器");
}
public Tiger(String tigerName, int tigerAge) {
this("aaa");
this.tigerName = tigerName;
this.tigerAge = tigerAge;
System.out.println("这里是Tiger类的两参构造器");
}
}
[4]this调用构造器的规则
-
在构造器中调用其他构造器,this()语句必须在第一行
-
各个构造器之间调用不能形成闭环
循环调用逻辑如下:
- 一个构造器中调用其他构造器的操作只能有一个
4、继承
-
4.1 程序中的继承
在程序中,也能出现继承的关系,让一个类去继承另一个类.
比如 A类继承B类
- 出现继承的关系
- A类是B类的子类,或者称为派生类
- B类是A类的父类,或者称为超类,基类
- 子类可以直接拥有父类的成员(不是全部)
-
9.2 继承的语法格式
继承使用关键字 extends,表示继承的意思
注意: extend 本身含义,扩展,延伸
-
定义格式
class B{} class A extends B{} // A 继承 B类
-
继承的入门案例 – 子类拥有父类成员
/** * 定义的是 Teacher和Manager类的共性内容 * 姓名年龄 */ public class Person { String name ; int age; }
/** * 管理类,班主任类 */ public class Manager extends Person{ }
/** * 老师类 * 重复,只做一次 * 想法: * String name; * int age; * 换一个地方定义(共性抽取) * Teacher和Manager共用 * 使用Person中的成员 * Teacher继承Person */ public class Teacher extends Person{ }
public static void main(String[] args) { /** * 创建对象, Person的子类对象 * Person : Teacher,Manager */ Teacher teacher = new Teacher(); //teacher对象,调用成员变量 //teacher子类对象调用继承的成员变量 teacher.name = "张三"; teacher.age = 20; Manager manager = new Manager(); manager.name = "李四"; manager.age = 22; System.out.println("teacher.name = " + teacher.name); System.out.println("teacher.age = " + teacher.age); System.out.println("manager.name = " + manager.name); System.out.println("manager.age = " + manager.age); }
-
4.3 继承的好处
上面案例,使用程序中的继承,使用继承的好处:
-
减少代码量
-
复用性提高
-
继承的存在,导致了面向对象的最后一个特征多态
继承有弊端: 类和类之间的紧密性更强.(扩展性越差)
-
4.4. 继承后成员特点
-
[1]继承后成员变量特点
子类和父类中的成员变量同名
-
调用的使用: 子类自己有,使用自己的,子类没有,使用父类
public class Fu{ String s = "父类"; } public class Zi extends Fu{ String s = "子类"; } public static void main(String[] args) { //创建对象,子类对象 Zi zi = new Zi(); //子类对象,调用成员s System.out.println(zi.s); }
-
[2] super关键字
super关键字是超级的意思,在子类中调用父类的成员,使用此关键字
super.变量 调用父的成员变量
super.方法() 调用的是父类的成员方法
this表示当前对象,super表示父类在内存中的存储空间,不是对象
public class Fu{
String s = "父类";
}
public class Zi extends Fu {
String s = "子类";
public void print(){
String s = "方法";
System.out.println(s);
System.out.println(this.s);
System.out.println(super.s);
}
}
public static void main(String[] args) {
//创建子类对象,调用方法
Zi zi = new Zi();
zi.print();
}
-
[3] 继承后成员方法特点
**方法重写override:**子类父类出现了一模一样的方法,称为子类重写了父类的方法.又称为覆盖或者复写.
调用子类重写的方法,假如子类没有重写,调用父类的方法
public class Fu {
public void print(){
System.out.println("父类方法print");
}
}
public class Zi extends Fu {
/**
* 要重写父类的方法
* 直接复制
*/
public void print(){
System.out.println("子类方法print::重写");
}
}
public static void main(String[] args) {
//创建子类对象
Zi zi = new Zi();
zi.print();
}
-
[4] 方法重写的意义
继承本质是扩展的意思,延伸的意思,依靠方法的重写来实现
方法重写引入案例,理解重写的意义
/**
* 定义手机类
* 早年代手机
*/
public class Phone {
/**
* 定义手机的来电显示功能
* 数字移动电话
*/
public void showingCall(){
System.out.println("来电显示号码");
}
}
/**
* 新手机:
* 功能变强,但是原有功能继续复用
* 继承和方法重写的思想
*/
public class Iphone extends Phone {
//重写父的方法
//方法名字不变,用户不需要重新知
public void showingCall(){
//复用显示号码功能,父类的方法中,已经完成了
//调用父类的方法
super.showingCall();
//新增的功能
System.out.println("显示大头像");
System.out.println("归属地");
System.out.println("意思推销");
}
}
public static void main(String[] args) {
//创建手机对象
Phone phone = new Phone();
phone.showingCall();
System.out.println("==========");
//创建新手机对象
Iphone iphone = new Iphone();
iphone.showingCall();
}
- [5] 方法重写小问题
方法重写需要考虑权限的.保证子类方法的权限要大于或者等于父类方法权限
-
父类的方法权限是public
class Fu{ public void print(){} } class Zi extends Fu{ public void print(){} //正确 protected void print(){} //错误,权限降低 void print(){} //错误,权限降低 private void print(){} //错误,权限降低 }
-
父类的方法权限是protected
class Fu{ protected void print(){} } class Zi extends Fu{ public void print(){} //正确 protected void print(){} //正确 void print(){} //错误,权限降低 private void print(){} //错误,权限降低 }
-
父类方法权限是默认
class Fu{ void print(){} } class Zi extends Fu{ public void print(){} //正确 protected void print(){} //正确 void print(){} //正确 private void print(){} //错误,权限降低 }
-
如果父类的方法权限是private, 子类不知道该方法的存在,没有继承的说法
- [6] 继承后构造方法特点
构造方法特点: 子类的构造方法中,第一行存在隐式代码 (写不写都存在),代码是super(); 调用父类的无参数构造方法.
public class Fu {
public Fu(){
System.out.println("父类构造方法");
}
}
public class Zi extends Fu {
public Zi(){
super(); //调用父类的无参数构造方法.
System.out.println("子类构造方法");
}
}
- 子类的构造方法,无论重载多少个,第一行肯定也是super();
public class Zi extends Fu {
public Zi(){
super(); //调用父类的无参数构造方法.
System.out.println("子类构造方法");
}
public Zi(int a){
super(); //调用父类的无参数构造方法.
System.out.println("子类构造方法::重载的");
}
}
- 父类没有无参数构造方法,子类的构造方法中,super(传递参数)
- 父类中存在多个构造方法,子类的构造方法只要调用到其中的一个即可
public class Fu {
/**
* 父类的构造方法
* 加上参数,有参数的构造
*/
public Fu(int a){
System.out.println("父类构造方法" + a);
}
public Fu(String s){
System.out.println("父类构造方法" + s);
}
}
public class Zi extends Fu {
public Zi(){
//调用父类的无参数构造方法
//父类中没有无参数构造
//传递响应的参数
super(7);
}
public Zi(String s){
//调用父类构造方法,保证调用其中一个
super("字符串");
}
}
- 4.5继承特点
[1]单继承
一个类只能继承一个类,不允许同时继承多个类
class A extends B,C{} //不允许的行为
单继承存在局限性,解决局限性问题,接口的概念
[2]多层继承
class A extends B{}
class B extends C{}
//多层继承,允许实现
//class C extends Object{}
A类可以同是拥有B和C的成员, B只能拥有C的成员
A类中super调用的是B类成员,如果B类没有成员,调用C成员
Object类是java中的皇帝,所有的类都是Object子类
5、对象的多态性
引入 : 生活中的多态性! 你自己的身份是学生,你的身份职场精英,患者.在不同的时期不同环境,状态是不同的.
生活中的多态性: 一个事物具备的不同形态.
5.1 对象多态性前提
- 必须有继承或者是接口实现
- 必须有方法的重写
多态的语法规则: 父类或者接口的引用指向自己的子类的对象
父类 变量(对象名) = new 子类对象(); //多态写法
对象调用方法,执行的子类的方法重写
5.2 多态中成员的特点
-
多态中成员变量的特点
- 编译 : 父类中没有成员变量,编译失败
- 运行 : 运行父类中的成员变量
-
多态中成员方法的特点
- 编译 : 父类中没有成员方法,编译失败
- 运行 : 运行子类的方法重写
-
简练 : 成员方法编译看左边,运行看右边.成员变量都是左边
Person p = new Student();
public class Person {
String s = "父类成员";
public void eat(){
System.out.println("人在吃饭");
}
}
public class Student extends Person {
String s = "子类成员";
public void eat(){
System.out.println("学生吃饭");
}
}
public static void main(String[] args) {
Person p = new Student();
//对象p,子类对象,调用成员变量s
System.out.println(p.s);
//子类对象调用方法
p.eat();
}
5.3 多态的转型
多态的程序中,不能调用子类的特有成员!!
只能调用子类父类的共有成员!!
转后类型 变量名 = (转后类型)要转的数据; //公式
public static void main(String[] args) {
//创建对象,多态性
//父类 = new 任意子类对象() 扩展
Animal animal = new Cat();
animal.eat();
//Cat类的特有功能 catchMouse()方法
//类型转换,强制
//Cat提升为了Animal,转回Cat类型
Cat c = (Cat)animal;
c.catchMouse();
}
补充: 多态性提升扩展性,是否需要强制转换,根据实际功能需求来决定.
5.4 多态中的转型异常
异常ClassCastException 类型转换异常,在多态中经常发生.
是在进行类型的强制转换的时候发生,我们现在的案例是Dog不能转成Cat.
需要解决这个异常 : 对象是Cat转Cat,是Dog换Dog
运算符 : 比较运算符,结果是boolean类型
运算符是关键字 instanceof
instanceof的语法格式:
对象名 instanceof 类的名字
解析: 比较这个对象,是不是由这个类产生的
c instanceof Cat 解释: c对象是不是Cat类产生的,如果是结果就是true
强制类型转换之前的安全性判断
public static void main(String[] args) {
//多态创建对象
Animal animal = new Dog();
animal.eat();
//判断 animal是不是Cat类的对象
//boolean b = animal instanceof Dog ;
//System.out.println(b);
//调用子类的特有方法
if (animal instanceof Cat){
//if为true,强制转换为Cat
Cat c = (Cat)animal;
c.catchMouse();
}
if (animal instanceof Dog){
Dog d = (Dog)animal;
d.lookHome();
}
}
- 抽象类 abstract
抽象的概念 : 凡是说不清楚的都是抽象
例子 : 我买了一台手机,买了一直笔,都是抽象概念.
具体: 华为Meta40Pro ,金属, 16G+512
程序中 : 我知道这个功能存在,但是怎么完成就说不清楚,程序中也出现了抽象.
6、 抽象
6.1方法定义
使用关键字 abstract定义抽象方法
权限修饰符 abstract 返回值类型 方法名字(参数列表) ;
abstract关键字
抽象方法没有方法体, 不需要{},直接分号结束
当一个类中的方法是抽象方法的时候,这个类必须是抽象类,在类的关键字class前面使用abstract修饰.
public abstract class 类名{}
public abstract class Animal {
/**
* 动物吃什么?
* 说不清楚,抽象,可以不说
*/
public abstract void eat();
}
6.2 抽象类的使用方式
- 抽象类不能实例化对象,不能new对象.
- 为什么不能建立对象,类中有没有主体的方法存在,建立对象调用抽象方法是绝对的错误,因此不能建立对象.
- 需要子类继承抽象类,重写抽象方法.
- 创建子类对象
- 使用多态性创建对象,调用方法执行子类的重写
public class Cat extends Animal{
/**
* 重写父类的方法
* 去掉修饰符 abstract
* 添加主体 {}
*/
public void eat(){
System.out.println("猫吃鱼");
}
}
public static void main(String[] args) {
//创建Animal的子类对象
Animal animal = new Cat();
//eat方法不可能执行父类,运行子类的重写
animal.eat();
}
6.3 抽象类中成员的定义
[1]抽象类中能否定义成员变量
可以定义成员变量,成员变量私有修饰,提供方法 get/set,由子类的对象使用
public abstract class Animal {
//抽象类中能否定义成员变量
private String name;
public abstract void eat();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//animal对象调用方法 get/ set
animal.setName("tom");
String name = animal.getName();
System.out.println(name);
}
[2] 抽象类中有构造方法吗
抽象类中有构造方法,不写有默认的
public abstract class Animal {
public Animal(){
System.out.println("Animal的构造方法");
}
public Animal(String name){
this.name = name;
System.out.println("有参数String的构造方法");
}
//抽象类中能否定义成员变量
private String name;
public abstract void eat();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Cat extends Animal {
public Cat(){
//调用父类的有参数构造方法
super("张三");
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
[3] 抽象中能否不定义抽象方法
抽象类中,可以不定义出抽象方法.
但是,如果有抽象方法存在,这个类必须是抽象类
6.4 子类还是抽象类的问题
当一个子类继承一个抽象类的时候,子类必须重写全部的抽象方法.假如子类重写了部分抽象方法,这个子类依然还是抽象类.
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
/**
* Cat继承父类Animal,Cat类拥有了父类的成员
* 父类有什么,我就有什么
*/
public abstract class Cat extends Animal {
public void eat(){}
/**
* 方法sleep没有重写
* 还是一个抽象的方法
*/
// public abstract void sleep();
}
7、接口 interface
7.1 接口无处不在
身边的接口有哪些,笔记本上USB接口,HDMI,TypeC接口,插座
USB接口 : 连接鼠标,键盘,摄像头,手机,移动硬盘,电风扇.设备的工作原理不同,但是都可以连接到USB接口上,完成他的任务.说明了一个问题 : 这些设备都满足USB的接口规范!!
接口:就是一个规范,或者称为标准 , 无论什么设备,只要符合接口标准,就可以正常使用.
接口的扩展性很强大.
7.2 Java中接口定义
当一个抽象类中的所有方法全部是抽象的时候,可以将这个抽象类换一个更加贴切的名词,叫他接口. 接口是特殊的抽象类.
定义接口,使用关键字 interface
语法规范:
public interface 接口名{}
接口在编译后,依然还是.class文件
7.3 接口中成员定义 (JDK1.7 版本)
-
成员变量
-
成员变量的定义是具有固定格式
-
成员变量的修饰符是固定 public static final
public static final 数据类型 变量名 = 值 ;
-
-
成员方法
-
成员方法的定义是具有固定格式
-
成员方法的修饰符固定为 public abstract
public abstract 返回值类型 方法名(参数列表) ;
-
7.4接口的使用方式
- 接口不能建立对象,不能new
- 需要定义类,实现接口(继承类,在接口中称为实现,理解为继承)
- 实现接口,使用新的关键字 implements
- 实现的格式
class 类 implements 接口名{}
- 重写接口中的抽象方法
- 创建子类的对象
/**
* 定义好的接口
*/
public interface MyInterFace {
//接口的成员变量
public static final int A = 1;
//接口的成员方法
public abstract void myInter();
}
/**
* 定义MyInterFace接口的实现类
* 重写接口的抽象方法
*/
public class MyInterFaceImpl implements MyInterFace{
public void myInter(){
System.out.println("实现类实现接口,重写方法");
}
}
public static void main(String[] args) {
//创建对象,多态性,创建接口实现类的对象
MyInterFace my = new MyInterFaceImpl();
my.myInter();
//输出接口中的成员A的值
System.out.println(my.A);
}
接口的多实现
类和类之间单继承,局限性的问题.接口的出现,是对单继承的改良,允许一个类同时实现多个接口.
语法格式:
class 类名 implements 接口A,接口B{}
实现类,重写实现的多有接口中的抽象方法
public interface A {
public abstract void a();
}
public interface B {
public abstract void b();
}
/**
* 实现接口A和B
*/
public class C implements A,B{
@Override
public void a() {
System.out.println("重写A接口方法");
}
@Override
public void b() {
System.out.println("重写B接口方法");
}
}
public static void main(String[] args) {
C c = new C();
c.a();
c.b();
}
8、 静态修饰符
static修饰符 : 最早出现在main方法中.只能修饰成员,不能写在方法的内部,被static修饰的成员,静态成员变量和静态的成员方法.
-
8.1、 静态修饰成员变量
static 修饰的成员变量,是被所有的对象共享的数据.没有被static修饰的成员变量,是每个对象的独享数据或者是特有数据.
public class Person {
String name;
static String country = "中国";
}
public class StaticTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "张三";
Person p2 = new Person();
p2.name = "李四";
//使用对象p1修改变量country的值
p1.country = "美国";
System.out.println(p2.country);
}
}
- 8.2、 静态内存
- 静态成员内存的特点
- 静态成员跟随自己的类进入到元数据区(静态区域)
- 静态成员属于自己的类,不属于对象
- 静态成员进入内存后,赋默认值
- 静态成员变量的初始化实际早于对象
-
8.3、 静态成员的调用方式
静态的内存图中,已经很明白了,静态属于自己的类,不是对象,静态的调用方式应该是
类名.静态成员
Person.country ;//调用静态成员
public static void main(String[] args) {
System.out.println(Person.country);
Person p1 = new Person();
p1.name = "张三";
Person p2 = new Person();
p2.name = "李四";
//使用对象p1修改变量country的值
Person.country = "美国";
System.out.println(Person.country);
}
静态的调用方式是两种 : 类名调用,对象调用. 非静态成员调用只能对象.
静态成员调用方式只有类名. 非静态成员只能对象. 对象.静态调用方式,会被javac编译为类名调用.
-
8.4、 静态方法
静态方法直接类名调用. 静态方法中不能直接使用非静态成员.
为什么不能调用非静态成员
静态是先人,非静态是后人. 静态出现在内存的时间早于非静态
public class Person {
String name;
static String country = "中国";
/**
* 静态方法
*/
public static void eat(){
System.out.println("人在吃饭" + country);
System.out.println(name); //错误写法,不允许
}
}
静态内存优先于对象,在静态的方法中不能使用this和super
- 8.5 、main方法
public static void main(String[] args){
}
- main方法详解
- public 最大权限 : main方法的调用者是JVM
- static 无需对象,被类名直接调用,JVM启动的时候使用类名.main启动程序
- void 无返回值,调用者是JVM,方法的返回值都是返回给调用者,JVM不需要返回值,没有意义
- main 固定方法名称
- args 字符串的数组,JVM调用方法main必须传递参数,后期对JVM设置参数
- 8.6、 什么时候定义静态
- 静态成员变量 : 具体功能具体分析 .
- 当你需要定义一个类的时候,分析这个类new出来的对象,是否存在共享数据,如果有共享数据,应该定义为静态变量
- 静态成员方法 :
- 当你类中的方法,没有使用过非静态成员你的时候,应该定义为静态.
10、 四大权限
四大权限 public protected default private
private | default | protected | public | |
---|---|---|---|---|
同一类 | OK | OK | OK | OK |
同一包 | NO | OK | OK | OK |
不同包子类 | NO | NO | OK | OK |
不同包非子类 | NO | NO | NO | OK |
- 受保护权限 protected
- 权限的成员,为子类提供使用
- Object类是所有类的父类,类中的方法权限有public,protected
- 关键的方式受保护权限的方法只能是 子类中super调用!!
- 子类对象不能调用,不出子类
11、 final修饰符
final修饰符是最终的意思,不可改变.final可以修饰类,修饰方法,修饰成员变量,修饰局部变量.
-
11.1、 final修饰类
被final修饰的类,称为最终类,不能被其他的类继承,无子类. 太监类.
学过的final类有哪些, String,System,Scanner.
public final class A{} //这个类A,不能出现子类,如果继承,直接报错
public class B extends A{} //错误,编译错误,最终类不能继承
-
11.2、 final修饰方法
被final修饰的方法,最终方法,不能被子类重写,和调用无关.
一个类中的部分方法很完美,但是另一部分方法有待完成,设计为两个部分.完美的方法就是final
public class A{
public final void a(){} //方法不能被子类重写
}
public class B extends A{
public void a(){} //最终方法,不能重写
}
-
11.3、 final修饰局部变量
变量定义在方法的内部,是局部变量, 被final修饰后,一次赋值,终身不改变,锁死了变量的值,看做是常量.
- final修饰的基本类型,锁死值
- final修饰的引用类型,锁死内存地址 (引用类型中的成员不受影响)
- final修饰了方法的参数,调用者传递值后,方法的参数值就锁死
public static void main(String[] args) {
/**
* Student student 对象存储的是内存地址
* final修饰后,固定住的,不可改变是student变量保存的地址
* 但是,Student对象中的成员,不受影响
*/
final Student student = new Student();
student.age = 20;
student.age = 30;
System.out.println(student.age);
final int[] arr = {1,2,3};//arr变量的值,固定为内存地址,不可改变
arr[1] = 200;
show(5);
}
public static void show(final int x){
x = 6; //final修饰,不可改变,报错
}
}
-
11.4、 final修饰成员变量
成员变量的定义位置,是在类中,方法外面.成员变量在内存中有默认值.final修饰成员变量的时候,锁住的不是内存默认值,而是我们程序人员手动的赋值.
- 成员变量赋值,可以定义直接写值
int age = 0;
- 成员变量赋值,可以使用构造方法
public Student(int age){this.age=age;}
- 成员变量赋值,可以使用set方法完成
- final修饰的成员变量,可以构造方法赋值,不能set方法赋值
- 构造方法在new对象的时候,执行一次,仅仅一次
- 可set方法,反复执行!!
public class Student {
final int age ;
public Student (int age ){
this.age = age;
}
/*public void setAge(int age){
this.age = age;
}*/
}
12、 代码块
-
12.1 静态代码块
写在类中方法外面 : static{}
静态代码块的执行时机 : 只要使用了这个类的成员(new对象,调用静态方法,静态变量),静态代码块就会执行,而且就一次
后面的课程会自己写静态代码块 : 数据库连接池 (C3P0,Druid)
JDBC注册数据库驱动程序,使用代码块
-
12.2 构造代码块
写在类中方法外面的 {}, 创建对象的时候运行,new一次,运行一次
-
12.3 局部代码块
写在方法内部的 {} 局部代码块,没有用
13. 对象的初始化过程(子类和父类)
- 父类.class文件先进入内存
- 子类.class文件再进入内存
- 初始化父类的静态成员(变量,代码块,方法)
- 初始化子类的静态成员
- 运行父类的静态代码块
- 运行子类的静态代码块
- 运行父类的构造代码块
- 运行父类的构造方法
- 运行子类的构造代码块
- 运行子类的构造方法
14. 内部类
概述 : 所谓内部类,就是在一个类的内部,定义了另外的一个类
class A{ //外部类,封闭类
class B{} //内部类,嵌套类
}
对象是生活中的存在的事物,一个事物中还存在着另一个具体的事物
class 大楼{
class 电梯{}
}
-
14.1、 成员内部类
成员内部类,是一个类定义在了另一个类的成员位置.这个内部类可以使用成员修饰符,public static final private .
对于内部来说 : 可以直接使用外部类的成员,如果外部类要使用内部类的成员,必须要创建对象.
//公式 : 外部类名.内部类名 = new 外部类对象().new 内部类对象()
//外部类
public class Outer {
public void outer(){
System.out.println("外部类的方法outer");
}
//内部类
public class Inner{
public void inner(){
System.out.println("内部类的方法inner");
}
}
}
public static void main(String[] args) {
//调用内部类的方法inner()
Outer.Inner oi = new Outer().new Inner();
oi.inner();
}
问题 : 内部类Inner,编译后有class文件吗?有class文件,名字是外部类$内部类
内部类也是类,继承Object,可以实现接口
内部类是静态的调用方式 : 外部类名.内部类名 变量名 = new 外部类.内部类()
-
14.2、 局部内部类
局部内部类 : 要定义在方法里面. 方法里面是局部位置,不能使用成员修饰符,权限,静态不能用
class A{
public void a(){
class B{} //局部内部类
}
}
public class Outer {
/**
* Inner类,是方法Outer的局部
* 依然方法,才能被外界访问
*/
public void outer(){
class Inner{
public void inner(){
System.out.println("局部内部类的方法!!");
}
}
//方法,建立对象
Inner inner = new Inner();
inner.inner();
}
}
public static void main(String[] args) {
//调用内部类的方法inner()
//直接调用,不能调用
Outer outer = new Outer();
outer.outer();
}
局部内部类,访问局部变量,变量必须final修饰
-
14.3、 匿名内部类
匿名内部类,就是没有名字的内部类,只能写在方法中,为了简化代码书写.
简化 : 实现类,实现接口,重写方法,创建对象. 或者是子类继承父类,重写方法,创建对象.代码上少内容.
-
匿名内部类使用的前提 :
-
必须有接口实现,或者是类的继承
-
格式 :
new 接口或者父类(){ //重写抽象方法 }; 格式 == 实现类,实现接口,重写方法,创建对象
public interface MyInter { public abstract void inter(); public abstract void inter2(); }
public class InnerClassTest { public static void main(String[] args) { //匿名内部类,简化书写,不写实现类 //同时调用多个重写方法 /* * new MyInter(){}; 是接口实现类的匿名对象 * 多态 : 接口 变量 = 实现类对象 */ MyInter my = new MyInter(){ @Override public void inter() { System.out.println("实现类实现接口重写方法"); } @Override public void inter2() { System.out.println("实现类实现接口重写方法2222"); } }; my.inter(); my.inter2(); } }
-
15、非法修饰符组合
非法的修饰符的组合,主要说的是抽象abstract
- abstract和private就是非法组合,抽象方法要重写,private不能继承
- abstract和final就是非法组合,抽象方法要重写,final修饰不能重写
- abstract和static就是非法组合,静态方法类名直接调用