网站首页 > 精选教程 正文
面向对象编程思想
一、什么是面向对象编程思想?
面向对象编程(OOP,Object-Oriented Programming)是一种程序设计范式,强调使用“对象”来表示和操作真实世界中的事物。通过抽象、封装、继承和多态等特性,OOP使得软件系统更加模块化、可维护和可扩展。具体来说:
- 对象:对象是现实世界中实体的抽象表示,拥有属性(数据)和方法(行为)。
- 类:类是对象的蓝图或模板,定义了对象的属性和方法。可以认为,类是对象的类型或种类。
- 抽象:通过忽略不必要的细节,聚焦于关键特征和行为,形成概念模型。
- 封装:将数据和方法包装在一个单元内,保护数据不被外界随意访问,通过方法来控制和修改。
- 继承:一个类可以继承另一个类的属性和方法,形成类的层次结构,促进代码重用。
- 多态:对象可以表现出多种形式,通常通过方法重载或方法覆盖实现,增加程序的灵活性。
二、类和对象
1. 定义类
类是对象的模板,定义了对象的属性和方法。属性用于描述对象的特征,方法用于描述对象的行为。以下是一个更详细的Book类示例:
public class Book {
// 属性
private String title; // 书名
private String author; // 作者
private String publisher; // 出版社
private double price; // 价格
private boolean isBorrowed; // 是否借出
// 构造方法
public Book(String title, String author, String publisher, double price) {
this.title = title;
this.author = author;
this.publisher = publisher;
this.price = price;
this.isBorrowed = false;
}
// 方法
public void printInfo() {
System.out.println("书名: " + this.title);
System.out.println("作者: " + this.author);
System.out.println("出版社: " + this.publisher);
System.out.println("价格: " + this.price);
System.out.println("是否借出: " + (this.isBorrowed ? "是" : "否"));
}
public void borrowBook() {
if (!this.isBorrowed) {
this.isBorrowed = true;
System.out.println("图书《" + this.title + "》已借出。");
} else {
System.out.println("图书《" + this.title + "》已被借出,无法再次借出。");
}
}
public void returnBook() {
if (this.isBorrowed) {
this.isBorrowed = false;
System.out.println("图书《" + this.title + "》已归还。");
} else {
System.out.println("图书《" + this.title + "》当前未被借出。");
}
}
}
2. 创建对象
对象是类的实例,每个对象都有自己独特的属性值。使用new关键字可以创建对象,并通过构造方法初始化属性。例如:
// 创建Book对象
Book book1 = new Book("《编程思想与算法》", "张三", "计算机出版社", 45.0);
Book book2 = new Book("《数据结构与算法》", "李四", "科技出版社", 50.0);
3. 使用对象
通过对象名访问属性和调用方法,例如:
// 打印图书信息
book1.printInfo();
book2.printInfo();
// 借出和归还图书
book1.borrowBook();
book1.returnBook();
4.对象在内存中的存储
5.对象之间的交互
Cat类:
public class Cat {
String name;
//抓老鼠
void catchMouse(Mouse m)// Mouse mouse=new Mouse 形参
{
m.hp--; //形参做更改了
System.out.println(this.name+"抓"+m.name);
System.out.println(m.name+"的生命值为:"+m.hp);
}
}
Mouse类:
public class Mouse {
String name;
int hp=3;
public Mouse()
{
}
public Mouse(String name)
{
this.name=name;
}
void eat(String food)
{
System.out.println(this.name+"吃"+food);
}
void cry()
{
System.out.println("555555");
}
}
#
三、类的组成
1、成员变量
成员变量也称为属性,在类里面,方法外面定义,并且不加static修饰符,在创建对象时实例化。
成员变量可被类中的方法、构造方法以及特定类的语句块访问。
如果声明成员变量时没对其初始化,则系统会使用默认值初始化成员变量。
[public|protected|private][static][final]<type> <variable_name>
各参数的含义如下。
- public、protected、private:用于表示成员变量的访问权限。
- static:表示该成员变量为类变量,也称为静态变量。
- final:表示将该成员变量声明为常量,其值无法更改。
- type:表示变量的类型。
- variable_name:表示变量名称。
private String name;
访问:
在类内部:
在类外部:
2、成员方法
普通成员方法:
静态成员方法:
方法上加static的方法
3、构造函数
构造方法是一个特殊的方法,通过构造方法可以完成对象的创建,以及实例变量的初始化。
当一个类没有提供任何构造方法,系统会默认提供一个无参数的构造方法。(此构造方法被称为缺省构造器)
当一个类中手动的提供了构造方法,那么系统将不再提供无参数的构造方法。
构造函数的特点:
1.构造函数名和类名相同
2.一个类可以有多个构造函数
3.构造函数没有返回类型
构造函数的调用:
使用new运算符来调用构造方法
Person p=new Person()
案例:
public class Person {
//属性 成员变量:在类里面 方法外面定义 并且不加static修饰符 创建对象以后 才会分配内存空间 并且每个对象都有自己的一份成员变量
//成员变量定义好以后 有默认值 String null int 0 char '' float 0.0 boolean false
String name;
int age;
char sex;
float h;
//每个类会有一个默认的构造函数,但如果自己定义了构造函数 则默认的构造函数会被覆盖
//特点:构造函数没有返回类型的
// 构造函数的名字和类名相同
// 可以有多个构造函数
// 构造函数是在new关键字后调用的 不能用对象名调用
public Person() {
// TODO Auto-generated constructor stub
System.out.println("55555");
}
//构造函数的重载: 方法名相同 参数列表不同 参数列表不同:参数个数不同或参数类型不同
public Person(String name,int age,char sex,float h)
{
//在类内部访问成员变量的时候 用this this:指的是当前对象
this.name=name;
this.age=age;
this.sex=sex;
this.h=h;
}
//构造函数如果传参 一般是用来给成员变量赋初始值的
public Person(String name)
{
this.name=name;
}
//行为 成员方法 在类内部定义 不加static的方法 创建对象以后 才会分配地址空间
//在类外 访问成员变量和成员方法的时候 需要用对象名来访问
void eat()
{
System.out.println("吃饭");
}
//函数可以传递参数
void eat(String food)
{
System.out.println(this.name+"吃"+food);
}
void sleep()
{
System.out.println("睡觉");
}
void dadoudou()
{
System.out.println("打豆豆");
}
}
4、重载方法
成员方法和构造方法都可以实现方法重载
方法重载是指:在同一个类中,方法名相同,参数列表不同(参数列表不同包括参数个数不同或参数类型不同)
案例:利用方法重载计算不同图形面积
public class AreaCalculator {
public double calculateArea(double r) {
return Math.PI * r * r;
}
public double calculateArea(double l, double w) {
return l * w;
}
public double calculateArea(double a, double b, double c) {
double s = (a + b + c) / 2;
return Math.sqrt(s * (s - a) * (s - b) * (s - c));
}
public double calculateArea(double a, double b) {
return Math.PI * a * b;
}
}
class Main {
public static void main(String[] args) {
AreaCalculator calculator = new AreaCalculator();
// 计算圆形面积
double circleRadius = 3.0;
double circleArea = calculator.calculateArea(circleRadius);
System.out.println("圆形面积: " + circleArea);
// 计算矩形面积
double rectLength = 5.0;
double rectWidth = 4.0;
double rectArea = calculator.calculateArea(rectLength, rectWidth);
System.out.println("矩形面积: " + rectArea);
// 计算三角形面积(使用海伦公式)
double a = 3.0, b = 4.0, c = 5.0;
double triangleArea = calculator.calculateArea(a, b, c);
System.out.println("三角形面积: " + triangleArea);
// 计算椭圆面积
double ellipseA = 2.0;
double ellipseB = 2.0;
double ellipseArea = calculator.calculateArea(ellipseA, ellipseB);
System.out.println("椭圆面积: " + ellipseArea);
}
}
5、静态变量、静态方法和静态块
1、静态变量
定义与特点:
- 静态变量又称为类变量。
- 静态变量属于类本身,而不是类的实例(对象)。
- 所有对象共享同一个静态变量,修改一个实例的静态变量会影响其他实例。
用途:
- 常用于记录与类相关的数据,如计数器、常量等。
示例:
public class Person {
public static int count = 0;
public Person() {
count++;
}
public static void main(String[] args()) {
Person p1 = new Person();
Person p2 = new Person();
System.out.println(Person.count); // 输出: 2
}
}
在上述例子中,count是一个静态变量,用于记录Person类的实例数量。每次创建一个Person对象,构造方法会将count加1。因此,p1和p2都共享同一个count变量,输出结果为2。
2、静态方法
定义与特点:
- 静态方法属于类,可以通过类名调用,无需创建类的实例。
- 静态方法在类加载时就已经存在于内存中。
- 静态方法不能直接访问非静态成员变量或方法,因为非静态成员在对象创建时才分配内存。
用途:
- 提供类级别的功能,方便使用。
- 将与类相关的功能组织在一起,提升代码的可维护性。
示例:
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
public static double getCircleArea(double radius) {
return Math.PI * radius * radius;
}
}
通过调用类名即可使用静态方法,无需实例化MathUtils:
int sum = MathUtils.add(5, 3);
double area = MathUtils.getCircleArea(4.0);
3、静态块
定义与特点:
- 静态块是在类加载时自动执行的一段代码。
- 静态块通常用于初始化静态变量或执行类加载时的操作。
- 每个类可以有多个静态块,执行顺序按照它们在类中的顺序。
用途:
- 初始化静态变量。
- 加载外部资源,如配置文件、驱动等。
- 执行类级别的初始化操作。
示例:
public class Logger {
static {
System.out.println("Logger类加载完成");
}
public static void log(String message) {
System.out.println("Log: " + message);
}
}
当Logger类被加载时,静态块会执行,输出“Logger类加载完成”。
4、总结
- 静态变量:共享于所有实例,适合需要跨实例保持状态的数据。
- 静态方法:属于类,方便调用,不依赖于特定实例,适合类级别的功能。
- 静态块:在类加载时执行,用于初始化或设置与类相关的资源和环境。
通过合理使用静态成员,可以提高Java程序的效率和组织代码结构,使程序更清晰、易于维护。
四、类的三大特征
1、封装
类的封装,是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类所提供的方法来实现对内部信息的操作访问。
一般通过get和set方法实现对成员变量的封装
2 、继承
1.什么是继承
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
多个类可以称为子类,单独这个类称为父类、超类或者基类。
2.语法
class SubDemo extends Demo{}
3.继承的特点
子类继承父类 会拥有父类中所有非私有的属性和方法 java是单继承, 一个子类只能继承一个父类。 Object是java中所有类的祖先即根类。 一个父类可以有多个子类
4.继承中构造函数的问题
在继承中,默认调用了父类的无参构造函数 ,创建了父类对象 , 父类的成员变量和成员方法才能创建出来, 子类才能继承下来使用。 父类如果没有无参构造函数 怎么办? 1.加一个无参的 2.手动调用父类有参的构造函数
public Dog(String name)
{
super(name);
System.out.println("创建了一只狗");
}
5.继承中重写的问题
方法重写:方法名相同,参数列表也相同,重写后的访问控制符的范围不能比重写前的小。
//重写
public void print()
{
super.print(); //super 关键字 父类或超类 调用父类中被覆盖的方法
System.out.println("等级:"+this.level);
}
3、多态
1. 什么是多态
多态是指一个对象可以呈现出多种形态,具体表现为方法重载和方法覆盖。方法重载是在同一类中定义多个方法名称相同但参数列表不同的方法。方法覆盖是在子类中重新定义超类中的方法,通常以实现不同行为。
在Java中,多态的实现主要依赖于父类引用指向子类实例。通过这种方式,可以使用父类类型的变量来调用实际子类对象的方法,从而实现动态方法调度。
2. 多态的使用
2.1 父类引用指向子类实例
多态的核心在于使用父类类型的引用(变量)指向子类的实例。这种引用称为“上转型变量”。以下是具体的实现方式:
// 定义一个父类Animal
public class Animal {
public void sound() {
System.out.println("动物发出声音。");
}
}
// 定义一个子类Dog,继承自Animal并重写sound()方法
public class Dog extends Animal {
@Override
public void sound() {
System.out.println("狗吠叫。");
}
}
// 使用父类引用指向子类实例
Animal animal = new Dog();
在上述代码中,animal是Animal类型的引用,但它指向的是Dog类的实例。当调用animal.sound()方法时,实际执行的是Dog类中重写的sound()方法,输出“狗吠叫。”
2.2 上转型变量的特点
- 可以访问从父类继承下来的属性和方法:通过上转型变量,可以访问父类定义的所有公共成员(属性和方法)。
- Animal animal = new Dog();
animal.sound(); // 输出“狗吠叫。” - 但不能访问子类特有的属性和方法:如果子类定义了新的属性或方法,上转型变量无法直接访问它们。
- // 假设Dog类有一个特有的方法cry()
public class Dog extends Animal {
public void cry() {
System.out.println("狗叫。");
}
}
Animal animal = new Dog();
animal.cry(); // 编译错误,Animal类没有cry()方法 - 如果子类将父类的属性和方法重写了,访问的是重写后的:子类可以重写父类的方法,此时上转型变量调用方法时,执行的是子类重写的方法。
- public class Animal {
public void eat() {
System.out.println("动物吃。");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃。");
}
}
Animal animal = new Dog();
animal.eat(); // 输出“狗吃。” - 可以强制转换为子类类型:为了访问子类特有的属性或方法,可以将上转型变量强制转换为子类类型。在进行类型转换之前,建议使用instanceof关键字检查对象的实际类型,以确保类型安全。
- if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.cry(); // 输出“狗叫。”
}
2.3 示例代码详解
下面通过一个详细的示例来进一步理解多态的使用。
示例:动物发出声音
// 定义父类Animal
public class Animal {
public Animal(String name) {
this.name = name;
}
protected String name;
public void sound() {
System.out.println(name + "发出声音。");
}
public void eat() {
System.out.println(name + "在吃。");
}
}
// 定义子类Dog,继承自Animal
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void sound() {
System.out.println(name + "叫。");
}
public void cry() {
System.out.println(name + "吠。");
}
}
// 定义子类Cat,继承自Animal
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void sound() {
System.out.println(name + "喵。");
}
public void scratch() {
System.out.println(name + "在挠痒。");
}
}
// 测试类
public class PolymorphismTest {
public static void main(String[] args) {
// 使用父类引用指向子类实例
Animal dog = new Dog("小黑");
Animal cat = new Cat("小白");
// 调用重写的方法
dog.sound(); // 输出“小黑叫。”
cat.sound(); // 输出“小白喵。”
// 调用父类的方法
dog.eat(); // 输出“小黑在吃。”
cat.eat(); // 输出“小白在吃。”
// 需要使用子类特有的方法时,进行类型转换
if (dog instanceof Dog) {
Dog realDog = (Dog) dog;
realDog.cry(); // 输出“小黑吠。”
}
if (cat instanceof Cat) {
Cat realCat = (Cat) cat;
realCat.scratch(); // 输出“小白在挠痒。”
}
}
}
输出结果:
小黑叫。
小白喵。
小黑在吃。
小白在吃。
小黑吠。
小白在挠痒。
解释:
- Animal dog = new Dog("小黑"); 和 Animal cat = new Cat("小白"); 是上转型变量的实例。
- dog.sound() 调用的是Dog类重写的sound()方法。
- cat.sound() 调用的是Cat类重写的sound()方法。
- dog.eat() 和 cat.eat() 调用的是父类Animal中的eat()方法,因为这两个子类并没有重写eat()方法。
- 当需要调用子类特有的方法(如cry()和scratch())时,需要进行类型转换。在转换之前,使用instanceof关键字检查以确保转换的安全性。
3. 多态的好处
- 灵活性:通过多态,可以使用统一的接口来处理不同类型的对象,这增强了程序的灵活性。
- 可扩展性:添加新的子类时,不需要修改现有的代码,只需确保子类正确实现父类的方法即可。
- 可维护性:代码的结构更加清晰,子类的实现与父类解耦,使得维护和扩展更加容易。
- 抽象性:通过多态,可以更好地实现抽象,关注接口而非具体实现细节。
4. 常见的多态术语
- 方法重载(Overloading):在同一个类中定义多个名称相同但参数不同的方法。
- 方法覆盖(Overriding):在子类中重新定义父类的方法,以实现特定行为。
- 上转型(Upcasting):将子类对象赋给父类引用,自动进行的转换。
- 下转型(Downcasting):将父类引用强制转换为子类类型,需确保类型安全。
- 动态方法调度(Dynamic Method Dispatch):在运行时根据实际对象类型决定调用哪个方法。
5. 多态的实际应用场景
- 图形绘制:通过多态,可以统一处理不同的图形类型(如圆形、矩形、正方形等),调用各自的绘制方法。
- 支付系统:支持多种支付方式(如现金、信用卡、电子钱包等),通过多态统一调用支付接口。
- 游戏角色:不同类型的角色(如士兵、法师、弓箭手)具有不同的技能和行为,可以通过多态实现角色行为的多样化。
6. 注意事项
- 方法重写时注意访问权限:子类重写的方法的访问权限不能比父类更严格,否则会导致编译错误。
- 使用@Override注解:在方法重写时,使用@Override注解可以帮助检查方法是否正确重写父类方法,增强代码的可读性和安全性。
- 类型转换的安全性:在进行下转型之前,确保对象的实际类型是目标子类类型,避免ClassCastException。
- 避免过度使用多态:虽然多态增强了程序的灵活性,但过度使用可能导致代码难以理解和维护,需要在灵活性和可读性之间找到平衡。
7. 总结
多态是Java面向对象编程的核心特性之一,通过方法重载和方法覆盖,实现了对象的多种形态。通过父类引用指向子类实例,可以动态地调用子类的方法,增强了程序的灵活性和可扩展性。在实际开发中,合理利用多态可以提高代码的可维护性和可复用性,是开发高质量软件的重要手段。
五、包和访问控制符
1、包
打包:package
导入包:import
2、访问控制符
Java 提供了三个访问控制符:private、protected 和 public ,另外还有一个不加任何访问控制符的访问控制级别。
其四种访问级别关系由小到大为 private->default->protected->public
private 访问控制级别:如果一个成员使用该控制符来修饰,则这个成员只能在该类的内部被访问。通常用于修饰属性,使用 private 来修饰属性可以把属性隐藏在类的内部。 default 访问控制级别(包访问权限):若一个成员不适用任何控制修饰符,则称它为默认访问控制,default 访问控制成员可被相同包下其它类访问。 protected 访问控制权限(子类访问权限):被修饰的成员既可被同一个包中其他类访问,也可被不同包中的子类访问。一般情况下,如果使用 protected 修饰一个方法,通常是希望其子类来重写这个方法。 public 访问控制权限(公共访问权限):是最宽松的访问控制级别,被 public 修饰的成员可被所有类访问
六、抽象类
1. 什么是抽象方法
1.1 定义
抽象方法是在面向对象编程(OOP)中,一个声明没有实现的方法。它只定义方法的名称、返回类型和参数列表,而不提供具体的执行代码。抽象方法用于定义类的一些行为,但具体如何实现则由其子类决定。
1.2 特点
- 没有方法体:抽象方法以分号结束,而不是使用花括号包裹代码块。
- 只能存在于抽象类或接口中:在Java中,一个类如果包含抽象方法,则必须被声明为抽象类。
- 必须由子类实现:如果一个类继承了包含抽象方法的抽象类,子类必须提供该方法的具体实现,除非子类本身也是抽象类。
1.3 用途
- 模块化和分离关注点:通过抽象方法,可以将方法的定义和实现分离,让不同部分处理不同的任务。
- 提供灵活性:子类可以根据自身需求选择如何实现抽象方法,从而提供不同的功能。
- 减少代码重复:多个子类可以继承相同的抽象方法,避免重复代码,提高代码可维护性和复用性。
1.4 示例
在Java中,抽象方法的定义如下:
public abstract class Shape {
public abstract double area();
}
子类Circle可能实现它:
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
在这个例子中,area()作为抽象方法被声明,Circle类提供了具体的实现。
2. 什么是抽象类
2.1 定义
抽象类是一种无法被实例化的类,旨在被其他类继承。它可能包含抽象方法(无实现的方法)和具体方法(有实现的方法)。抽象类提供了一种更高级的模板,为其子类提供共同的属性和方法。
2.2 特点
- 不能实例化:试图创建抽象类的实例会导致编译错误。
- 可以包含抽象和具体方法:抽象类可以定义一些方法必须由子类实现,同时也提供一些已经实现的方法供子类使用。
- 通过继承实现代码复用:抽象类促进代码复用,子类继承其属性和方法,可以在此基础上添加更多功能。
- 提升层次结构的清晰度:抽象类有助于建立清晰的类层次结构,使得类间的关系更加明确和有序。
2.3 用途
- 定义公共接口或基类:抽象类为一组相关子类提供一个公共的基类,定义它们共享的属性和方法。
- 提供基础实现:抽象类可以实现一些常用的功能,子类无需重复实现,而专注于自身的特定功能。
- 灵活性和可扩展性:抽象类允许子类根据需要添加或修改功能,同时保持一定的统一性和一致性。
2.4 示例
public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public abstract void sound();
public String getName() {
return name;
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void sound() {
System.out.println("Dog barks");
}
}
在这个例子中,Animal是抽象类,声明了抽象方法sound()和具体方法getName()。Dog类继承自Animal,并提供了sound()的具体实现。
总结
- 抽象方法是没有实现的方法,用于定义接口和让子类提供具体实现。
- 抽象类是不能被实例化的类,旨在被继承,通常包含抽象方法和具体方法,用于提供公共的属性和行为,以及促进代码复用和模块化设计。
七、接口
1.什么是接口
Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)
2.接口的作用
有利于代码的规范性
有利于代码的维护
3.接口的使用规范
1、接口当中不能够定义变量,但是可以定义常量
假如你在接口当中定义属性,那么,通过反编译可以看见他会自动使用public static final修饰。
接口当中的属性都是全局静态常量,接口当中的常量一定要在定义的时候,指定初始值。
2、接口当中,所有的方法都是抽象方法
接口中方法都会自动用public abstract修饰,也就是接口当中只有全局抽象方法。
3、接口不可以实例化,接口中不可以有构造。
4、接口之间能够通过extends实现继承关系,一个接口能够继承多个接口,但是接口不可以继承类。
5、接口的实现类必须实现接口的全部方法,不然的话就必须定义成抽象类。
八、综合案例--通过面向对象思想实现新闻管理系统
代码:
news类:
package mm;
public class News {
private int id;
private String title;
private String content;
public int getId() { return id; }
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public News() {
}
public News(int id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
}
service接口层:
package com.test.service;
import com.test.pojo.News;
public interface INewsService {
public void addNews(News news);
public void printAllNews();
}
impl层:
package com.test.service.impl;
import com.test.pojo.News;
import com.test.service.INewsService;
public class NewsService implements INewsService {
private News[] newsList;
private int index=0;
public NewsService(int n)
{
this.newsList=new News[n];
}
@Override
public void addNews(News news) {
this.newsList[index++]=news;
}
@Override
public void printAllNews() {
for(int i=0;i<index;i++)
System.out.println(this.newsList[i]);
}
}
测试:
package com.test;
import com.test.pojo.News;
import com.test.service.INewsService;
import com.test.service.impl.NewsService;
public class Test {
public static void main(String[] args) {
INewsService newsService=new NewsService(10);
newsService.addNews(new News(1,"aa","aaa"));
newsService.printAllNews();
}
}
九、内部类
将一个类定义在另一个给类里面或者方法里面,这样的类就被称为内部类。
创建内部类:
//高内聚
//低耦合
//可扩展性好
public class OuterClass {
private int a;
private static int aa;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public static int getAa() {
return aa;
}
public static void setAa(int aa) {
OuterClass.aa = aa;
}
public void outerFun()
{
System.out.println("外部类的方法 ");
//外部类不能直接访问内部类的信息
//只能通过创建内部类的对象来访问
InnerClass innerClass=new InnerClass();
innerClass.b=1;
}
class InnerClass
{
private int b;
private final static int bb=1; //常量 内部类中是不能定义静态变量 但是可以定义final static 类型的常量
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
public void innerFun()
{
System.out.println("内部类的方法");
a=1; //内部类中可以直接访问外部类的信息 内部类就相当于是外部类的一个成员属性
OuterClass.this.a=1;
}
}
}
如何在类外访问:
//在类外 访问外部类 的方法
OuterClass outerClass =new OuterClass();
outerClass.setA(12);
outerClass.outerFun();
//在类外 访问外部类 的方法
OuterClass.InnerClass innerClass=outerClass.new InnerClass();
innerClass.innerFun();
匿名内部类:
public interface IFind {
public void find();
}
public static void test(IFind iFind)
{
iFind.find();
}
public static void main(String[] args) {
test(new IFind() {
@Override
public void find() {
System.out.println("从数组中查找");
}
});
}
十、异常
1.什么是异常
异常是程序运行过程中出现的错误
2.异常类的结构图
3.错误和异常的区别
Thorwable类是所有异常和错误的超类,它有两个子类Error和Exception,分别表示错误和异常。
1.Error
Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
2.Exception
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
4.异常的分类
异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception )和检查异常(Checked Exception )。
1.运行时异常
运行时异常都是RuntimeException类及其子类异常,如NullPointerException.(indexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生。
2 非运行时异常
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。程序运行之前会报错。提示你添加try catch捕获,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。 如IOExceptionsQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
5.捕获异常
//尝试去执行
try {
//如果在try中遇到异常 则直接抛出异常对象 跳转到catch中捕获 try后面的语句不执行
Teacher teacher=null; //NullPointerException new NullPointerException()
teacher.eat();
int[] a=new int[5];
System.out.println(a[5]);
//一个try可以跟多个catch 但一次只能进到一个catch
} catch (NullPointerException e) { //捕获异常 //Exception e=new NullPointerException()
System.out.println("catch1:"+e.getMessage());
return; //遇到return 语句 后面的代码不执行 但finally除外
}
catch(IndexOutOfBoundsException e2)
{
System.out.println("catch2:"+e2.getMessage());
}
finally{
System.out.println("finally中的语句永远都执行,哪怕前面有return语句");
}
6.异常捕获注意事项
- try不能单独存在
- try catch try--finally try--catch--finally都是可以的
- 一个try可以跟多个catch但一次只能执行其中一次catch
- 如果在try中遇到异常那么try中后面的语句不会执行
- finally永远都执行哪怕前面遇到return
7 自定义异常
自定义异常:
public class MyException extends Exception{
private String message="年龄不合法";
public String getMessage() {
return message;
}
}
可以手动抛出异常:
int age;
age=-5;
try {
if(age<0)
throw new MyException(); //手动抛出异常
} catch (MyException e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
}
也可以在方法上抛出:
public class Person {
//将抛出的异常给上一层处理
void checkAge(int age) throws MyException
{
if(age<0)
throw new MyException();
}
}
Person person=new Person();
try {
person.checkAge(-5);
} catch (MyException e) { // //这里可能会抛出一个异常
e.printStackTrace();
}
十一、综合案例---在之前的新闻管理系统上添加异常处理
添加自定义异常类
package com.test.exception;
public class ArrayLengthException extends Exception {
private String message="数组长度不合法";
@Override
public String getMessage() {
return this.message;
}
}
修改NewsService类:
package com.test.service.impl;
import com.test.exception.ArrayLengthException;
import com.test.pojo.News;
import com.test.service.INewsService;
public class NewsService implements INewsService {
private News[] newsList;
private int index=0;
//添加异常处理
public NewsService(int n) throws ArrayLengthException {
if(n<=0)
throw new ArrayLengthException();
this.newsList=new News[n];
}
@Override
public void addNews(News news) {
this.newsList[index++]=news;
}
@Override
public void printAllNews() {
for(int i=0;i<index;i++)
System.out.println(this.newsList[i]);
}
}
测试:
public static void main(String[] args) {
INewsService newsService= null;
try {
newsService = new NewsService(-3);
newsService.addNews(new News(1,"aa","aaa"));
newsService.printAllNews();
} catch (ArrayLengthException e) {
e.printStackTrace();
}
}
猜你喜欢
- 2025-05-08 1.5、Java面向对象编程:类与对象、继承、多态、封装
- 2025-05-08 Java中的面向对象编程思想深度解读
- 2025-05-08 Java中的面向对象编程思想(java面向对象编程原则)
- 2025-05-08 Java的"两面性":面向对象与元编程技术的共生之道
- 2025-05-08 java面向对象编程(Java面向对象编程孙卫琴 电子版)
- 2025-05-08 Java 学习之面向对象思想、类、对象
- 2025-05-08 此继承非彼继承,今天说的是面向对象的基本特征之一
- 2025-05-08 揭秘Java中的面向对象模型(java面向对象几大特征)
- 2025-05-08 快速对比理解,编程中,什么是面向对象,什么是面向过程
- 2025-05-08 java面向对象三大特性:封装、继承、多态——举例说明(转载)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)