Java面向对象
编辑时间:2021/03/08
读完本节:大概花费35分钟,共3574词
1.对多态的理解:
-
实现代码的通用性
-
Object类中定义的public boolean equals(Object obj){}
JDBC:使用Java程序操作(获取数据库连接、CRUD)
-
因为抽象类、接口不能实例化,所以抽象类和接口的使用体现了多态
2.多态是编译时行为还是运行时行为?
-
多态是运行时行为,因为动态绑定的缘故,程序在编译期间并不知道具体要调用的哪个对象的方法,只有在运行期间程序执行到了确定位置才知道具体要调用的方法
-
举例:比如使用随机数来确定要实例化的对象 ,这个时候在编译的期间无法知到实例化的是哪个对象,只用在程序真正运行的时候才能知道。
package randomObject; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/8 11:21 * @Description: */ public class RandomObjectTest { public static void main(String[] args){ int random = (int)(Math.random() * 2 + 1); // System.out.println(random); if(random == 1){ Person person = new Teacher(); System.out.println(person); }else{ Person person = new Student(); System.out.println(person); } } }
3.static关键字
-
当编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时候系统才会分配内存空间给对象,其方法才可以供外部调用;有时候希望无论是否产生了对象,或者无论产生了多少对象的情况下,某些特定的数据在内存空间中只有一份,这个时候就可以使用static关键字。
-
static可以用来修饰属性、方法、代码块、内部类
-
使用static修饰属性:静态变量(类变量)
-
按是否使用static修饰,分为静态属性和非静态属性(实例变量),一个属性被static修饰则称该属性为静态属性
实例变量:创建了类的多个对象,每个对象都独立拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性其值发生改变
静态变量:创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时是修改过的。
-
静态变量修饰属性时,该属性随着类的加载而加载,可以通过“类.静态变量”的方式进行调用;静态变量的加载要早于对象的创建;由于类只会加载一次,则静态变量在内存中也只会存在一份(存在于方法区的静态域中)。
类变量 实例变量 类被加载时 可以访问 不可以访问 对象被加载时 可以访问 可以访问 -
静态属性举例:System.out;Math.PI等
-
类变量和实例变量的内存解析:
-
-
使用static修饰方法:静态方法
-
静态方法随着类的加载而加载,可以通过“类.静态方法”的方式进行调用
静态方法 非静态方法 类被加载时 可以访问 不可以访问 对象被加载时 可以访问 可以访问 -
静态方法中,只能调用静态的方法或属性,main方法是一种静态方法。
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。
-
-
static关键字使用注意点:
-
在静态方法内,不能使用this关键字、super关键字。静态方法、常量是放在data segment区域的,而this和super关键字的使用得先实例化对象,而实例化的对象存在heap中,所以静态方法无法调用this、super关键字
-
关于静态属性和静态方法的使用,可以从生命周期的角度理解
-
在开发中如何确定一个属性是否要声明为静态的?
属性是可以被多个对象所共享的,不会随着对象的不同而不同
类中的常量通常也声明为静态的
-
在开发中如何确定一个方法是否要声明为静态的?
操作静态属性的方法,通常设置为静态的
工具类的方法,习惯上声明为静态的,如Math、Arrays、Collections
-
-
static关键字练习:
package StaticTest; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/8 13:14 * @Description: */ public class CircleTest { public static void main(String[] args){ Circle circle1 = new Circle(); circle1.setRadius(2.1); Circle circle2 = new Circle(3.2); System.out.println("Circle1的id是:" + circle1.getId()); System.out.println("Circle1的面积是:" + circle1.findArea()); System.out.println("Circle2的id是:" + circle2.getId()); System.out.println("Circle2的面积是:" + circle2.findArea()); System.out.println("Circle的个数是:" + Circle.getTotal()); } } class Circle{ private double radius;//半径 private int id;//编号 private static int total;//记录创建圆的总数 private static int init = 1001;//初始圆的个数,被所有的对象所共享 //在构造器中计数 public Circle(){ id = init++; total++; } public Circle(double radius){ this(); this.radius = radius; } //求圆的面积 public double findArea(){ return Math.PI * radius * radius; } //提供getter和setter public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } public int getId() { return id; } public static int getTotal() { return total; } }
4.设计模式之单例模式
-
设计模式:大量的实践中总结和理论化之后的优选代码结构、编程风格、以及解决问题的思考方式。
-
所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果要让一个类在虚拟机中只能产生一个对象,首先必须将类的***构造器的访问权限设置为private***,这样就不能够用new操作符在类的外部产生类的对象了,但是在类的内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能***调用该类的某个静态方法***以返回类内部创建的对象,静态方法只能访问类中的静态成员的变量,所以指向类内部产生的***该类对象的变量也必须定义成静态的***。
-
23种设计模式:
创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
-
单例模式实现举例:
饿汉式:
package singleton_test; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/8 13:43 * @Description: singleton的饿汉式实现 * 实现步骤: * 1. 私有化类的构造器 * 2. 内部创建类的对象 * 3. 提供公共的静态方法,返回类的对象 * 4. 要求此对象也必须声明为静态的 */ public class SingletonTest1 { public static void main(String[] args){ ClassA classA1 = ClassA.getInstance(); ClassA classA2 = ClassA.getInstance(); System.out.println(classA1 == classA2); } } class ClassA{ //1. 私有化构造器 private ClassA(){ } //2. 内部创建类的对象;4. 要求此对象也必须声明为静态的 private static ClassA instance = new ClassA(); //3. 提供公共的静态方法,返回类的对象 public static ClassA getInstance(){ return instance; } }
懒汉式:
package singleton_test; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/8 13:43 * @Description:singleton的懒汉式实现 * 实现步骤: * 1. 私有化类的构造器 * 2. 内部创建类的对象 * 3. 提供公共的静态方法,返回类的对象 * 4. 要求此对象也必须声明为静态的 */ public class SingletonTest2 { public static void main(String[] args){ ClassB classB1 = ClassB.getInstance(); ClassB classB2 = ClassB.getInstance(); System.out.println(classB1 == classB2); } } class ClassB{ //1. 私有化构造器 private ClassB(){ } //2. 内部创建类的对象;4. 要求此对象也是静态的 private static ClassB instance = null; //3. 要求提供公共的静态方法,返回类的对象 public static ClassB getInstance(){ if(instance == null){ instance = new ClassB(); } return instance; } }
-
区分饿汉式和懒汉式
饿汉式:缺点:对象加载时间过长;优点:饿汉式的线程是安全的
懒汉式:缺点:线程不安全;优点:延迟对象的创建,减少内存的占用
-
单例模式的优点:
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多资源时,如读取配置、产生其他以来对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
-
单例设计模式的应用场景:
网站计数器:一般也是单例模式实现,否则难以同步
应用程序的日志应用:一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加
数据库连接池:数据库连接是一种数据库资源,不可能在每次访问都新建一个对象完成连接
项目中,读取配置文件的类:一般也只有一个对象。没有必要每次都是用配置数据文件,都生成一个对象去读取
Application,典型的单例模式
Windows的Task Manager(任务管理器)也是单例模式
Windows的Recycle Bin(回收站)也是典型的单例应用,在整个系统运行的过程中,回收站一直维护着仅有的一个实例
5.关于main方法:
-
main()方法作为程序的入口
-
main()方法也是一个普通的静态方法
-
main()方法可以作为域控制台交互的方式
public class MainDemo{ public static void main(String[] args){ for(int i = 0;i < args.length;i++){ System.out.println("*****" + args[i]); int num = Integer.paraseInt(args[i]); System.out.println("#####" + num); } } }
在命令行中先使用javac对java源文件进行编译,生成字节码文件,然后使用”java 文件名 参数“的方式进入程序并与程序进行交互
6.类的成员 - 代码块
-
代码块(初始化块、block)
-
代码块的作用:用来初始化类、对象
-
代码块只能使用static修饰
-
代码块的分类:静态代码块、非静态代码块
-
静态代码块:内部可以有输出语句;代码块随着类的加载而执行,而且只执行一次。
静态代码块的作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
-
非静态代码块:内部可以有输出语句;代码块随着对象的创建而执行,每创建一个对象,就执行一次非静态代码块。
非静态代码块的作用:可以在创建对象时,对对象的属性进行初始化
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
非静态代码块内可以调用静态的属性、静态的方法或非静态的属性、非静态的方法
-
-
LeafTest
package leaftest; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/8 19:06 * @Description: */ class Root{ static{ System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } public Root(){ super(); System.out.println("Root的无参构造器"); } } class Mid extends Root{ static{ System.out.println("Mid的静态初始化块"); } { System.out.println("Mid的普通初始化块"); } public Mid(){ super(); System.out.println("Mid的无参构造器"); } } class Leaf extends Mid{ static{ System.out.println("Leaf的静态初始化块"); } { System.out.println("Leaf的普通初始化块"); } public Leaf(){ super(); System.out.println("Leaf的无参构造器"); } } public class LeafTest { public static void main(String[] args){ new Leaf(); System.out.println("*************"); new Leaf(); System.out.println("*************"); new Mid(); } }
结果:
7.属性的赋值过程
-
对于属性可以赋值的位置
①默认初始化
②显示初始化
③构造器中初始化
④有了对象之后,可以通过“对象.属性”或“对象.方法”的方式进行赋值
⑤在代码块中赋值
赋值顺序
① - ②/⑤ - ③ - ④
package ordertest; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/8 19:24 * @Description: */ public class OrderTest { public static void main(String[] args){ Order order = new Order(); System.out.println(order.orderId); } } class Order{ int orderId = 3; { int orderId = 4; System.out.println(orderId); } }
8.final关键字
-
final可以用来修饰的结构:类、方法、变量
-
final用来修饰一个类:表示此类不可以再被其他类所继承
比如String类、System类、StringBuffer类
-
final用来修饰方法:表示此方法不可以被重写
比如Object类中的getClass()
-
final用来修饰变量:表示此时的变量是一个常量
比如Math.PI
- final修饰属性:可以考虑赋值的位置有:显示初始化、代码块中初始化、构造器中初始化
- final修饰局部变量:基本数据类型:值不可更变;引用数据类型:引用地址值不可更变
-
static final 用来修饰属性则该属性称为全局常量
static可以修饰属性、方法、代码块、内部类;final可以修饰类、方法、变量。公共子集只有属性和方法。