Java面向对象
面向对象 OOP
-
object-oriented programming
-
java编程核心思想就是面向对象
-
面向对象三大特性
①封装 | ②继承 | ③多态 -
对于描述复杂的事物,为了从宏观上把握、 从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
什么是面向对象
- 面向对象的本质:以类的方式组织代码,以对象的方式组织(封装)数据。
- 抽象
- 三大特性:封装+继承+多态
- 类是对象的模板、抽象;对象是类的具体实例
package com.ylq;
public class Demo01 {
public static void main(String[] args) {
System.out.print(whoMax(99,97));
}
public static int whoMax(int x, int y){
return x>y? x:y;
}
// 修饰符 返回值类型 方法名(参数列表){
// 方法体
// return [返回值];
// }
}
- break: ①跳出switch ②跳出循环
- continue:跳出一次循环
- return: 方法结束
- static修饰符
1 可以支持起 类.方法 的调用,不然的话得 对象.方法 来调用。
2 static加载的时间很早,和类一起加载。没有static的要在类实例化以后才加载。
package com.ylq;
public class Demo02 {
public static void main(String[] args) {
Archer shiLang = new Archer();
shiLang.selfIntroduction();
shiLang.setNew(shiLang,1,"卫宫士郎");
shiLang.selfIntroduction();
}
}
class Archer {
int id = 0;
String name = "吉尔伽美什";
public static void setNew(Archer newOne,int id,String name) {
newOne.id = id;
newOne.name = name;
}
public void selfIntroduction() {
System.out.println("I\'m an Archer,"+name+",ID"+id); }
}
上例中因为传递的参数是一个对象,故属于引用传递。方法内部的赋值行为会影响方法外部。
类与对象的创建
tips:
一个程序最好只有一个main方法,是程序的入口
一般会创建一个主启动类Application,在这个类中写main方法
类的构造器
一个类即使什么都不写也会自动生成一个构造方法,如如上例中的
Archer()
构造方法也可以显示地定义:
- 必须与类同名,而且不能写返回值类型(void也不能写)
- 显示定义可以用来初始化一些信息
- 可以无参构造也可以有参构造
- new关键字本质是调用构造器
- 定义有参构造的时候必须显示地定义一个无参构造
- intelij IDEA用快捷键alt+insert可以快速创建构造器
package com.ylq.demo03;
public class Ninja {
int id;
String name;
public Ninja() {
this.id = 0;
this.name = "小胖";
}
public Ninja(int fpID,String fpName){
this.id = fpID;
this.name = fpName;
};
public void selfIntroduce() {
System.out.println("我是"+this.name+",NO."+this.id+".");
}
}
package com.ylq.demo03;
public class Application {
public static void main(String[] args) {
Ninja xiaoPang = new Ninja();
xiaoPang.selfIntroduce();
Ninja longMa = new Ninja(1,"龙马");
longMa.selfIntroduce();
}
}
Java内存分析
面向对象三大特性
封装
- 高内聚,低耦合:
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
- 低耦合:尽量暴露少量的方法给外部使用。
- 数据的隐藏:通常,应禁止直接访问一个对象中的·实际表示,而应通过操作接口来访问。
- 属性私有private,get/set
- set方法中经常会做一些安全性验证。
- 封装的意义:
1.提高程序的安全性,保护数据
2.隐藏代码的实现细节
3.统一接口
4.系统可维护性增加了
继承
-
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
-
extends的意思是“扩展”。子类是父类的扩展。
-
JAVA中的类只有单继承,没有多继承!
-
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
-
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
-
子类和父类之间,从意义上讲应该具有“is a”的关系。
-
object类
-
super
-
方法重写
-
ctrl+h可以查看继承树
package com.ylq.demo05;
public class Spirit {
private int id;
private String name;
public Spirit() {
}
public Spirit(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.ylq.demo05;
public class Rider extends Spirit {
private String mountName;
public Rider() {
}
public Rider(int id, String name) {
super(id, name);
}
public Rider(String mountName) {
this.mountName = mountName;
}
public Rider(int id, String name, String mountName) {
super(id, name);
this.mountName = mountName;
}
public String getMountName() {
return mountName;
}
public void setMountName(String mountName) {
this.mountName = mountName;
}
public void selfIntroduce(){
System.out.println("我是Rider,真名"+this.getName()+",ID"+this.getId()+",我的坐骑是"+getMountName()+".");
}
}
package com.ylq.demo05;
public class Application {
public static void main(String[] args) {
Rider medusa = new Rider(1,"美杜莎","小白马");
medusa.selfIntroduce();
}
}
-
Java中所有的类都默认直接或间接继承Object类
-
调用子类的无参构造的时候默认隐式调用父类无参构造
-
想显示调用父类构造器super()必须放在第一行
-
构造器中调用本对象的构造器this()也必须放在第一行
-
故上面两个构造器调用只能用一个
super
和this一样都是代词。super可以指代父类对象,甚至可以指代父类构造函数。
方法重写
- 需要有继承关系,子类重写父类的方法!
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小 public > protected > default > private
- 抛出的异常:范围可以缩小但不能扩大 ClassNotFoundException --> Exception
下例中的非静态写法就是方法的重写
package com.ylq.demo06;
public class Father {
public static void test() {
System.out.println("测试了父类");
}
public void testWithoutStatic() {
System.out.println("测试了父类withoutStatic");
}
}
package com.ylq.demo06;
public class Son extends Father {
public static void test() {
System.out.println("测试了子类");
}
public void testWithoutStatic() {
System.out.println("测试了子类withoutStatic");
}
}
package com.ylq.demo06;
public class Application {
public static void main(String[] args) {
Son pang = new Son();
pang.test();
//静态方法:
//分别调用Father和Son的test
//方法的调用只和左边定义的数据类型有关系
//父类的引用指向子类
Father shou = new Son();
shou.test();
//非静态方法:
//都是调用Son的test
//方法的调用只和构造函数的引用有关
//子类重写了父类的方法
pang.testWithoutStatic();
shou.testWithoutStatic();
//结果:
//测试了子类
// 测试了父类
//测试了子类withoutStatic
// 测试了子类withoutStatic
}
}
不能重写的情况
-
static 方法属于类,不属于实例
-
final 常量
-
private 私有的方法
修饰符public \ protected \ default \ private
类内部 | 本包 | 子类 | 外部包 | |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
多态
- 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
- 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多(一般是父类或有关系的类)
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 注意: 多态是方法的多态,属性没有多态(同重写)
- instanceof 引用类型间的类型转换,测试某对象是否属于特定类
package com.ylq.demo07;
public class Application {
public static void main(String[] args) {
Object naMei = new Navigator();
System.out.print((naMei instanceof Navigator)+" | "); // √
System.out.print((naMei instanceof Pirate)+" | "); // √
System.out.print((naMei instanceof Object)+" | "); // √
System.out.print((naMei instanceof Captain)+" | "); // ×
System.out.print((naMei instanceof Warrior)+" | "); // ×
System.out.print((naMei instanceof String)+" | \n"); // ×
System.out.println("---------------------------------------");
Pirate luFei = new Captain();
System.out.print((luFei instanceof Navigator)+" | "); // ×
System.out.print((luFei instanceof Pirate)+" | "); // √
System.out.print((luFei instanceof Object)+" | "); // √
System.out.print((luFei instanceof Captain)+" | "); // √
System.out.print((luFei instanceof Warrior)+" | "); // ×
//System.out.print((luFei instanceof String)+" | \n"); 编译时报错
System.out.println("---------------------------------------");
Warrior zoro = new Warrior();
//System.out.print((zoro instanceof Navigator)+" | "); 编译时报错
System.out.print((zoro instanceof Pirate)+" | "); // √
System.out.print((zoro instanceof Object)+" | "); // √
//System.out.print((zoro instanceof Captain)+" | "); 编译时报错
System.out.print((zoro instanceof Warrior)+" | "); // √
//System.out.print((zoro instanceof String)+" | \n"); 编译时报错
System.out.println("---------------------------------------");
}
}
- 强制类型转换
- 类型转换低转高,可以自动转换;高转低,需要强制类型转换
- 引用型数据中:父类-高,子类-低
- Object obj = String(); 左高右低,低转高,自动转换
- 子类强转父类会丢失一些方法
多态小结:
- 父类的引用指向子类的对象
- 把子类转换为父类,向上转型
- 把父类转换为子类,向下转型,需要强制转换
- 方便方法的调用,减少重复的代码!简洁
Static详解
-
static的属性和方法属于类,不用实例化成对象就可以调用。
-
静态属性不因对象变多而增加,一直就一个。
-
静态方法在加载类的时候就加载了,存在堆得方法区中,可以直接 类.方法 调用
-
静态代码块:只在加载类的时候执行一次,在构造函数之前
static{
...
}
package com.ylq.demo08;
import org.w3c.dom.ls.LSOutput;
public class CodeBlock {
{
System.out.println("匿名代码块");
}
static{
System.out.println("静态代码块");
}
public CodeBlock() {
System.out.println("构造函数");
}
public static void main(String[] args) {
CodeBlock pang = new CodeBlock();
System.out.println("-----------------------");
CodeBlock shou = new CodeBlock();
}
}
/*
静态代码块
匿名代码块
构造函数
-----------------------
匿名代码块
构造函数
*/
- 静态导入包
import static java.lang.Math.random;
tips: final修饰的东西不能继承给子类,final修饰的类断子绝孙了
抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,→抽象方法、抽象类。
- 抽象类中可以没有抽象方法,但抽象方法的类一定要声明为抽象类。
- 抽象类,不能使用new关键字来创建对象,它是用来让子类实现的。
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
package com.ylq.demo09;
public abstract class Mood {
protected abstract void influence();
}
抽象类中的抽象方法可以只有名字,没有具体实现的代码
package com.ylq.demo09;
public class Happy extends Mood {
@Override
protected void influence() {
System.out.println("心情越快,乐观向上");
}
}
抽象类有局限性,因为继承的单继承特性。但是通过接口可以实现多继承。
故实际开发中接口用得比较多。
接口
-
普通类:只有具体实现。
-
抽象类:具体实现和规范(抽象方法)都有!
-
接口:只有规范,自己无法写方法。体现了约束和实现分离。
-
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是。。则必须能。。”的思想。如果你是坏人,则必须欺负好人。
-
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
-
OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象
-
声明类的关键字是class,声明接口的关键字是interface
-
接口中的方法默认都是public abstract
-
接口的实现类一般以impl结尾(implement使实现)
-
接口中定义的属性都默认为常量,省略了public static final
package com.ylq.demo10;
public interface UserService {
int AGE = 20;
void add();
void delete();
void update();
void query();
}
package com.ylq.demo10;
public interface TimeService {
void setTime();
}
package com.ylq.demo10;
public class UserServiceImpl implements UserService,TimeService{
@Override
public void setTime() {
}
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void update() {
}
@Override
public void query() {
}
}
内部类
- 内部类就是在一个类的内部再定义一个类。
- 非静态内部类可以调用外部类的私有属性
- 静态内部类不能调用非静态外部类的私有属性
1.成员内部类
2.静态内部类
3.局部内部类 (比如在方法内写的类)
4.匿名内部类 (new Allpe.eat();没有把创建的对象指向任何引用名,直接用)
package com.ylq.demo11;
public class Outer {
private int id = 10;
public class Inner {
protected void letsGo(){
System.out.println("内部类起飞,还能输出外部类私有属性:"+id);
}
}
}
package com.ylq.demo11;
public class Application {
public static void main(String[] args) {
Outer littleBoy = new Outer();
Outer.Inner devil = littleBoy.new Inner();
devil.letsGo();
}
}