Java面向对象
面向过程&面向对象
静态对象与非静态对象
public class Demo01 {
public static void a() {
//非静态方法,必须实例化对象才可以调用
// b();
Demo01 demo01 = new Demo01();
demo01.b();
}
//非静态方法
public void b() {
//静态方法可以不实例化对象就可以使用,例如Demo01.a()
//因为静态方法是从属于类的
Demo01.a();
}
}
构造器
示例代码如下:
public class Person {
String name;
int age;
//使用new关键字,本质是在调用构造器,用来初始化值
//new Person()调用的就是这个
public Person() {
}
//有参构造:一旦定义了有参构造,无参就必须显式定义
// 与无参构造形成重载
public Person(String name) {
//注意this的使用
this.name = name;
}
//alt + insert是idea生成构造器的快捷键
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
创建对象的内存分析
示例分析
主类
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "小狗";
dog.age = 2;
dog.shout();
Pet cat = new Pet();
}
}
Pet类
package com.arioya.oop;
public class Pet {
String name;
int age;
public void shout() {
System.out.println(this.name + "吱啦一声");
}
}
类与对象小结
-
类与对象
类是一个模板:抽象,对象是一个具体的实例 -
方法
定义、调用!
对应的引用 -
引用类型
除了八个基本类型的类型都是引用类型
对象是通过引用来操作的:栈--->堆
-
默认初始化:
- 数字:0 0.日
- char :u0000
- boolean:false
- 引用:null
封装
用get和set方法提供专门接口,通过一些检测逻辑,可以确保对象的属性合法。是系统更合法
优点
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护性增加了
继承
如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法,继承的成员变量或方法的访问权限保持不变。
如果子类和父类不在同一个包中,那么,子类继承了父类的protected、public成员变量做为子类的成员变量,并且继承了父类的protected、public方法为子类的方法,继承的成员或方法的访问权限保持不变。
super关键字
子类可以隐藏从父类继承的成员变量和方法,如果在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。
//父类
public class Pet {
String name;
int age;
public Pet() {
System.out.println("Pet构造了");
}
public void shout() {
System.out.println(this.name + "吱啦一声");
}
}
//子类
public class Dog extends Pet{
public Dog() {
//super()是父类的无参构造,可以隐含不写,要写必须在第一行
/*
用子类创建对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将其中一部分(子类继承的那部分)作为分配给子类对象的变量。
*/
super();
System.out.println("Dog构造了");
}
public void shout() {
System.out.println("汪汪!");
}
public void text() {
this.shout();
//super可以调用继承自父类的方法和属性
super.shout();
}
}
//测试类
public class Application {
public static void main(String[] args) {
Dog dog = new Dog();
dog.shout();
}
}
小结
- super注意点
- super调用父类的构造方法,必须在构造方法的第一个
- super 必须只能出现在子类的方法或者构造方法中!
- super和 this 不能同时调用构造方法!
- super与this的对比
- 代表的对象不同:
this:本身调用者这个对象
super:代表父类对象的应用 - 前提
this:没继承也可以使用
super:只能在继承条件才可以使用 - 构造方法
this();本类的构造
super():父类的构造!
- 代表的对象不同:
成员变量的隐藏和方法重写
对于子类可以从父类继承的成员变量,只要子类中声明的成员变量和父类中的成员变量同名时,子类就隐藏了继承的成员变量,子类自己声明定义的方法操作与父类同名的成员变量是指子类重新声明定义的这个成员变量。
如果子类可以继承父类的某个实例方法,那么子类就有权利重写这个方法。重写是方法的重写,属性没有重写
-
重写的语法规则
-
方法重写是指:子类中定义一个方法,这个方法的类型和父类的方法的类型一致或者是父类的方法的类型的子类型,并且这个方法的名字、参数个数、参数的类型和父类的方法完全相同。
-
修饰符:范围可以扩大但不能缩小public > Protected > Default > private
-
抛出的异常:范围,可以被缩小,但不能扩大ClassNotFoundException --> Exception(大)
-
static,final,private修饰的方法无法被重写
-
-
重写的目的
子类通过方法的重写可以隐藏继承的方法,子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为。
//父类
public class Pet {
public void shout() {
System.out.println("宠物吱啦一声");
}
public static void happy() {
System.out.println("宠物要尾巴了");
}
}
//子类
public class Dog extends Pet{
//Override就是重写的意思,Alt + Insert插入
@Override
public void shout() {
System.out.println("汪汪!");
}
public static void happy() {
System.out.println("小狗摇尾巴了");
}
}
//调用类
public class Application {
public static void main(String[] args) {
//非静态方法重写
//父类引用指向子类,涉及多态
Pet pet1 = new Dog();
pet1.shout();
Dog dog1 = new Dog();
dog1.shout();
//静态方法没有重写,方法的调用只和左边,定义的数据类型有关,因为静态方法从属于类
Pet pet2 = new Dog();
pet2.happy();
Dog dog2 = new Dog();
dog1.happy();
}
}
多态
多态性就是指父类的某个方法被其子类重写时,可以各自产生自己的功能行为。多态是方法的多态,属性没有多态
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Dog();
//new Pet();
//可以指向的引用类型就不确定了:父类的引用指向子类
//Dog 能调用的方法都是自己的或者继承父类的
Dog dog = new Dog();
//Pet 父类型,可以指向子类,但是不能调用子类独有的方法
Pet dog1 = new Dog();
Object dog2 = new Dog();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大,dog1不能直接调用子类独有的方法,需要强制类型转换才能实现
((Dog) dog1).eat();
dog.eat();
}
}
对象的上转型对象
假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,比如:
这时,称对象a是对象b的上转型对象。
instanceof关键字
用于检测左侧的对象是否为右侧类或接口的实例。它返回一个布尔值,如果对象是指定类的实例或者是这个类的子类的实例,则返回true;否则返回false。
public class Application {
public static void main(String[] args) {
//Object > String
//Object > Pet > Dog
//Object > Pet > Cat
Object object = new Dog();
System.out.println(object instanceof Dog);//true
System.out.println(object instanceof Pet);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Cat);//False
System.out.println(object instanceof String);//False
System.out.println("----------------------------");
Pet pet = new Dog();
System.out.println(pet instanceof Dog);//true
System.out.println(pet instanceof Pet);//true
System.out.println(pet instanceof Object);//true
System.out.println(pet instanceof Cat);//False
// System.out.println(pet instanceof String);//编译报错
System.out.println("----------------------------");
Dog dog = new Dog();
System.out.println(dog instanceof Dog);//true
System.out.println(dog instanceof Pet);//true
System.out.println(dog instanceof Object);//true
// System.out.println(dog instanceof Cat);//False
// System.out.println(dog instanceof String);//编译报错
/*
总结:
当左边引用无关是报错,
引用有关,但不是继承实例的关系时为false
*/
}
}
类型转换
-
父类引用指向子类的对象
-
把子类转换为父类,向上转型,可能会丢失自己的本来的一些方法,也就说上面所说的对象的上转型对象
-
把父类转换为子类,向下转型:强制转换
-
强制转换方便方法的调用,减少重复的代码!
静态代码块
public class Person {
//一般对象赋初值
{
System.out.println("匿名代码块执行了");
}
//静态代码块只执行一次,从属与类,比匿名代码块和构造函数更先执行
static {
System.out.println("静态代码块执行了");
}
public Person() {
System.out.println("构造函数执行了");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("--------------");
Person person2 = new Person();
}
}
运行截图
抽象类和抽象方法
-
用关键字abstract修饰的类称为abstract类(抽象类)。
-
用关键字abstract修饰的方法称为abstract方法(抽象方法)
抽象方法只有方法名字,没有方法的实现
-
abstract类可以有abstract方法(抽象方法)也可以有非abstract方法。
-
抽象方法必须在抽象类中
-
对于abstract类,我们不能使用new运算符创建该类的对象。,只能靠子类实现他,
接口
为了克服Java单继承的缺点,Java使用了接口,一个类可以实现多个接口。
使用关键字interface来定义一个接口。接口的定义和类的定义很相似,分为接口的声明和接口体。
- 接口声明
接口通过使用关键字interface来声明,格式:
interface 接口的名字 - 接口体
接口体中包含常量定义和方法定义两部分。 - 接口的使用
一个类通过使用关键字implements声明自己实现一个或多个接口。 - 通过import语句引入包中的接口
import java.io.*;
//接口1
//抽象思维,架构师就是跟接口打交道的,要不断的提高
//interface 定义的关键字,接口都需要有实现类
public interface Action {
//常量,public static final
int age = 99;
//接口中的所有定义的方法其实都是抽象的public abstract(默认)
void dothing();
}
//接口2
public interface Sleep {
void hl();
}
//实现类
public class Person implements Action, Sleep{
@Override
public void dothing() {
}
@Override
public void hl() {
}
}
接口的作用
- 是用来约束实现功能的,定义一些方法,让不同的人实现
- 接口中默认有public abstract和public static final
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
- 必须要重写接口的方法
内部类
//外部类
public class Outer {
private int id = 10;
public void out() {
System.out.println("这是外部类方法");
}
//内部类
public class Inner{
public void in() {
System.out.println("这是内部类方法");
}
//内部类可以调用外部类的私有成员变量和方法
public void getID() {
System.out.println(id);
out();
}
}
}
//调用函数
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in();
inner.getID();
}
}
此外还有静态内部类,public static class,这时和外部类相同了,可以直接创建静态类内部对象。只有内部类才可以静态
还有局部内部类,在方法中定义的内部类
另外,一个文件中可以有多个类,但只能有一个public类
形式有很多
匿名类
public class Application {
public static void main(String[] args) {
//匿名类
//没有名字初始化类,不用讲实例保存到变量中
App app = new App(){
@Override
public void hello() {
}
};
}
}
interface App {
void hello();
}