面向对象技术利用对现实世界中对象的抽象和对象之间相互关联及相互作用的描述来对现实世界进行模拟,并且使其映射到目标系统中。其以基本对象模型为单位,将对象内部处理细节封装在模型内部,重视对象模块间的接口联系和对象与外部环境间的联系,能层次清晰地表示对象模型。面向对象的特点主要概括为抽象性、继承性、封装性和多态性。
5.1 对象特征
用来描述客观事物的一个实体,由一组属性和方法构成
-
属性
-
方法
package cn; public class User { //属性 成员属性 成员变量 private int id; private String name; private byte age; /** * 方法 成员方法 * @return */ public String showInfo() { return String.format("ID:%d,姓名:%s,年龄:%d岁。", id, name, age); } 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; } public byte getAge() { return age; } public void setAge(byte age) { this.age = age; } }
5.2 类 class
类就是一块模板,确定对象将会拥有的特征(属性)和行为(方法)
具有相同属性和方法的一组对象的集合
对象与类的关系
5.3 定义类
类是一种抽象数据类型,在Java中类也被当作一个数据类型来定义。类成员包括数据成员(成员变量)和方法成员(成员方法)。java.lang.Object 此类是java程序类的基类,声明定义的类,会自动继续Object类,java 类是单继承,多实现。
-
声明类
[public][abstract|final] class className [extends superclassName] [implements interfaceNameList] { 变量成员声明和初始化; 方法声明及方法体; }
package cn; import java.util.Date; public class A { } class C{ } class B extends C{ }
package cn; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; public class MyGui extends JFrame implements ActionListener { JButton btn = new JButton(); JButton exit = new JButton("退出软件"); public MyGui(String title) { super(title); setSize(500, 380); setLayout(null); btn.setText("打开百度"); btn.setBounds(100, 250, 100, 25); btn.addActionListener(this); add(btn); exit.setBounds(300, 250, 100, 25); exit.addActionListener(this); add(exit); setLocationRelativeTo(null); setDefaultCloseOperation(2); setVisible(true); } public void actionPerformed(ActionEvent e) { if (e.getSource() == btn) { int i = JOptionPane.showConfirmDialog(this, "要打开百度码?"); if (i == 0) { Runtime run = Runtime.getRuntime(); try { run.exec("cmd /k start http://www.baidu.com"); } catch (IOException e1) { e1.printStackTrace(); } } }else if(e.getSource() == exit) { this.dispose(); System.exit(0); } } public static void main(String[] args) { new MyGui("词典程序"); } }
5.3.1 定义属性
成员变量又可以叫做属性或字段。它是用来存储数据以记录对象的状态的
[public | protected | private ]
[static] [final] [transient] [volatile]
type variableName; int i;
其中, static: 静态变量(类变量)注:相对于实例变量
final: 常量
transient: 暂时性变量
volatile: 共享变量,用于并发线程的共享
- 实例变量
- 类变量
package cn;
public class My1 {
int age = 18;
static double money;
public static void main(String[] args) {
//方法一 在main方法如何要使用成员变量,java静态的方法可以直接使用静态成员
// 5行改为 static int age = 18;
//System.out.println(age);
System.out.println(money);//0.0
//方法二 在main方法如果要使用成员变量,可以实例化使用对象来调用
var m = new My1();
m.age = 25;
System.out.println(m.age);
m.show();
}
public void show() {
System.out.println(age);
}
}
-
成员变量和局部变量区别
5.3.2 定义方法
[public | protected | private ]
[static] [final | abstract]
[native] [synchronized]
returnType methodName([paramList])
[throws exceptionList] {
方法体(statements)
}
类方法定义案例
package cn.oop;
public class C1 {
public static void main(String[] args) {
System.out.println(getPf(17));// 289
var c = new C1();
System.out.println(c.getLf(3));// 27
c.show(9);
}
/**
* <p>desc: </p>
*
* @param i
* @return
*/
public static int getPf(int i) {
return i * i;
}
public void show(int i) {
System.out.printf("%d 的立方是:%d",i,getLf(i));
}
public int getLf(int i) {
return i * i * i;
}
}
package cn.oop;
public class C2 {
String i = "ok";
void m1() {
int i = 30;
System.out.println(i);
}
void m2() {
System.out.println(i);
int i = 60;
if(true) return;
System.out.println(i);
System.out.println(this.i);
}
void m3() {
System.out.println(i);
System.out.println(this.i);
{
int i = 100;
System.out.println(i);
System.out.println(this.i);
int a = 50;
}
int a = 1000;
System.out.println(a);
}
}
方法调用
方法常见概念 void 没有返回值 方法名 形参 实参 return; return 3; 方法返回值
-
方法 多个形参,形参的个数不确定
void show(){} int show(int i){return i*i;} int sum(int[] ns){return 0;} int sum(int...n){return 0;}
递归方法
方法中再次调用自己,
package cn.oop;
public class M2 {
static int i = 0;
/**
* 此方法就是递归方法,死循环
*/
public void m() {
m();
}
public void mm(int n) {
++i;
System.out.print(i + " ");
if(n>i) mm(n);
}
public static void main(String[] args) {
M2 m = new M2();
//m.mm(13);
m.m();
"*".repeat(3);
}
}
5.3.3 定义静态代码程序段
package cn.oop;
public class M3 {
static {
int age = 3;
System.out.println(age);
}
int age = 18;
static {
int age = 33;
System.out.println(age);
}
public void show() {
System.out.println("信息显示");
}
public static void main(String[] args) {
System.out.println("程序开始");
M3 m1 = new M3();
M3 m2 = new M3();
M3 m3 = new M3();
M3 m4 = new M3();
}
static {
int age = 333;
System.out.println(age);
}
}
5.4 实例化对象
5.5 抽象
5.6 构造方法
类的构造方法是特殊的方法,此方法名称必须和类名一致,构造不能有返回值 不使用void,不能直接调用,在类对象实例化时自动调用,new 的时候可以调用。一般构造方法用于类对象实例化时的初始化。如果一个类没有编写构造方法,系统自动给此类编译时添加一个无参构造方法。如果声明类编写了构造方法,系统不再添加无参构造方法,建议编写完构造方法时,最好编写一个无参构造方法。
package cn.oop;
public class M5 {
public M5(String title) {
}
public M5() {
}
public static void main(String[] args) {
var m1 = new M5();
var m2 = new M5("");
}
}
5.7 lombok组件
- 官方下载
也可以直接在eclipse中安装 https://projectlombok.org/p2
-
使用lombok快速生成getter setter 相关的代码
package cn.oop;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Data @AllArgsConstructor @NoArgsConstructor
public class Book {
private int bookId;
@Getter @Setter
private String name;
@Setter
private double price;
private String author;
}
5.8 封装
5.9 package包
包的作用:
1、组织相关的源代码文件
2、不同包中的类名可以相同,用来避免名字冲突
3、提供包一级的封装和存取权限
定义包名的语法:package 包名;
注意 1、定义包的语句必须放在所有程序的最前面
2、包定义语句不是必须的,如果没有定义包,则当前编译单元属于无名包,生成的class文件放在一般与.java文件同目录。
3、Java编译器会自动引入包java.lang,对于其他的包,如果程序中使用到包中的类,则必须使用import引入。
包名命名方法:
全部小写,公司网址倒写。
package com.baidu.wenku.ui;
package org.apache.commons.io;
abc.com
http://www.abc.com
cn.webrx;
package com.abc.oa.db;
5.10 类的继承extends
为什么使用继承:减少代码冗余,提高程序的复用度
UML 1.类图 2.用例图 3.时序图
统一建模语言(Unified Modeling Language,UML)是一种为面向对象系统的产品进行说明、可视化和编制文档的一种标准语言,是非专利的第三代建模和规约语言。UML是面向对象设计的建模工具,独立于任何具体程序设计语言。
访问修饰符 public private protected 保护 默认 friendly
访问修饰符 | 本类 | 同包 | 子类 | 其他实例对象 |
---|---|---|---|---|
private | √ | |||
默认(friendly) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
5.11 方法重写(覆盖)、重载
覆盖时必须是继承关系,子类对父类的方法不满意,重写。
5.12 抽象类 abstract class
package cn.webrx.abs;
/**
* 抽象类
*
* @author webrx
*
*/
public abstract class Abs1 {
/**
* 抽象方法
*
* @param i
* @return
*/
public abstract int getPf(int i);
/**
* 实现方法
* @param a
* @param b
* @return
*/
public int getSum(int a, int b) {
return a + b;
}
}
使用规则
1. 抽象类必须被继承,抽象方法必须被重写。
2. 抽象类中的抽象方法只需声明,无需实现;
3. 抽象类不能被实例化,抽象类不一定要包含抽象方法,而定义抽象方法的类必须是抽象类。
4.抽象类包含的抽象方法必须在其子类中被实现,否则该子类也必须是抽象类。
5.抽象类可以有构造方法供子类实例化对象
抽象类本质
1.从类的组成上看其是抽象方法和非抽象方法的集合。
2.从设计的角度来看,实际上抽象类定义了一套规范(抽象方法)。
5.13 接口 interface
package cn.webrx.in;
/**
* 接口是静态常量,和抽象方法的集合
* java 8.0 接口增加了静态实现方法和默认实现方法
* @author webrx
*
*/
public interface A {
public static final int AGE = 18;
// 接口中抽象方法,没有使用abstract 没有public 也是public
int getPf(int i);
public abstract int getLf(int i);
public default void hello(String name) {
System.out.println("hello :"+name);
}
public static void welcome(String name) {
System.out.println("welcome :"+name);
}
}
实现接口
package cn.webrx.in;
public class B implements A{
public int getPf(int i) {
return i*i;
}
public int getLf(int i) {
return i*i*i;
}
}
使用接口
package cn.webrx.in;
public class Test {
public static void main(String[] args) {
System.out.println(A.AGE);
A.welcome("李四");
A a = new B();
a.hello("张三丰");
System.out.println(a.getLf(3));
System.out.println(a.getPf(3));
}
}
package cn.ex;
public class Demo {
public static void main(String[] args) {
A a = new A();
B b = new A();
C c = new A();
}
}
class B {
}
interface C {
}
interface E {
}
interface D {
}
interface F extends C, D, E {
}
class A extends B implements F, C, D, E {
}
A a = new B();
(1)继承关系
class B extends A{
}
class A{
}
(2)接口实现关系
interface A{
}
class B implements A{
}
class A extends B implements C,D,E{
}
C c = new A();
B b = new A();
E e = new A();
5.14 抽象类和接口区别
abstract class Db{}
interface Db{}
企业框架开发中,使用接口比较多。
instanceof 判断一个对象是不个类的实例
public static int max(Object... o) {
int m = Integer.MIN_VALUE;
if (o.length == 0) {
m = 0;
} else if (o.length == 1) {
if (o[0] instanceof Integer) {
m = Integer.parseInt(o[0].toString());
} else if (o[0] instanceof int[]) {
for (int oo : (int[]) o[0]) {
if (m < oo)
m = oo;
}
}else if(o[0] instanceof int[][]) {
for(int[] ii : (int[][])o[0]) {
m = max(ii);
}
}
} else {
for (Object a : o) {
if (a instanceof int[]) {
if (m < max(a)) {
m = max(a);
}
} else {
if (a instanceof Integer && m < Integer.parseInt(a.toString())) {
m = Integer.parseInt(a.toString());
}
}
}
}
return m;
}
5.15 装箱、拆箱
Integer i1 = 128; // 装箱,相当于 Integer.valueOf(128);
int t = i1; //相当于 i1.intValue() 拆箱
基本类型和包装器类型的转换 List<int>错误,泛型不支持基本类型 List<Integer>正确
基本类型 | 包装器类型 |
---|---|
boolean | Boolean |
char | Character |
int | Integer |
byte | Byte |
short | Short |
long | Long |
float | Float |
double | Double |
5.16 静态
- 静态程序段
- 静态属性,类成员,可以直接通过类名直接访问
- 静态方法,可以直接通过类名直接调用
- 静态导入 import static java.lang.Math.PI;
package cn.ex;
import static java.lang.Math.PI;
import static java.lang.Math.pow;
public class StaticTest {
static {
for (int i = 1; i <= 5; i++) {
System.out.println(i);
}
}
static int i = 30;
public static void main(String[] args) {
System.out.println(PI);
System.out.println(i);
System.out.println(pow(2, 3));
System.out.println(getPf(3));
System.out.println(StaticTest.getPf(6));
}
public static int getPf(int i) {
return i * i;
}
}
5.17 内部类
- 类中包含
- 静态程序段
- 属性
- 方法
- 成员内部类,可以使用private修饰
package com.baidu.oa.dao;
public class A {
private class B {
}
public void show() {
class C{
}
DB dd = new DB() {
};
}
}
内部类的共性内部类分为: 成员内部类、静态嵌套类、匿名内部类。
(1)、内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
(2)、内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。
(3)、外部类不能直接访问其内部类,想要访问内部类,需实例化内部类
(4)、内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量。
(5)、其他类想要直接访问内部类,可直接实例化内部类,方法如下外部类名.内部类 对象名 = new 外部类().new 内部类();
例:Out.In in = new Out().new In();
如果内部类是静态的,当其他类调用内部类可直接通过类名调用,格式如下:
外部类.内部类 对象名 = new 外部类.内部类()
例:Out.In in2 = new Out.In();
当内部类是静态的,且方法也是静态的,此时可不需实例化对象
外部类.内部类.静态方法名();
例:Out.In.fun();
System.out.print();
作业
-
编写一个类,包含两个方法,一个方法是求和,别外一个方法是求出最大值。
-
问题
1)父类和子类的构造方法哪个先执行?
2)父类多个的构造函数中那个被执行?
2)如何指定执行父类某个特定的构造函数?
3)子类可以访问父类的私有成员吗?private 只本类中