个人网站的制作论文,南京一站式工程装饰装修网站,中国百科网vip钓鱼网站开发,如何注册企业网址文章目录 一、单例设计模式#xff08;1#xff09; 设计模式概述#xff08;2#xff09; 何为单例模式#xff08;3#xff09; 实现思路#xff08;4#xff09; 单例模式的两种实现方式1. 饿汉式2. 懒汉式3. 饿汉式 vs 懒汉式 #xff08;5#xff09; 单例模式的… 文章目录 一、单例设计模式1 设计模式概述2 何为单例模式3 实现思路4 单例模式的两种实现方式1. 饿汉式2. 懒汉式3. 饿汉式 vs 懒汉式 5 单例模式的优点及应用场景 二、理解main方法的语法1main()方法的剖析2与控制台交互1.举例11.1 方式一、命令行1.2 方法二、编译器 2.举例2 3笔试题 一、单例设计模式
1 设计模式概述
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
设计模式免去我们自己再思考和摸索。就像是经典的棋谱不同的棋局我们用不同的棋谱。“套路”
经典的设计模式共有23种。每个设计模式均是特定环境下特定问题的处理方法。
创建型模式主要用于创建对象根据不同场景设计不同的设计模式。 简单工厂模式并不是23中经典模式的一种是其中工厂方法模式的简化版 对软件设计模式的研究造就了一本可能是面向对象设计方面最有影响的书籍《设计模式》《Design Patterns: Elements of Reusable Object-Oriented Software》即后述《设计模式》一书由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著Addison-Wesley1995。这几位作者常被称为四人组Gang of Four而这本书也就被称为四人组或 GoF书。 2 何为单例模式
单例–单独一个实例对象
所谓类的单例设计模式就是采取一定的方法保证在整个的软件系统中对某个类只能存在一个对象实例不需要多个对象并且该类只提供一个取得其对象实例的方法。
3 实现思路
如果我们要让类在一个虚拟机中只能产生一个对象我们首先必须将类的构造器的访问权限设置为private这样就不能用new操作符在类的外部产生类的对象了但在类内部仍可以产生该类的对象。
因为在类的外部开始还无法得到类的对象只能调用该类的某个静态方法方法不能是非静态的因为非静态方法要通过对象去调用
此时外部无法创建对象来调用方法只能通过类调用静态方法以返回类内部创建的对象静态方法只能访问类中的静态成员变量所以指向类内部产生的该类对象的变量也必须定义成静态的。
4 单例模式的两种实现方式
1. 饿汉式
class Singleton {// 1.私有化构造器private Singleton() {}// 2.内部提供一个当前类的实例// 4.此实例也必须静态化private static Singleton single new Singleton();// 3.提供公共的静态的方法返回当前类的对象public static Singleton getInstance() {return single;}
}【举例】
场景假设Bank只有一个实例。
package yuyi04;public class BankTest {}class Bank{ //假设这个银行只有一个实例中国人民银行}①类的构造器私有化 (避免类的外部创建对象)
为了保证这个类只能造一个对象而造对象需要使用到构造器那么在这个类外面就不能让它随便调用构造器。
class Bank{ //假设这个银行只有一个实例中国人民银行//1.类的构造器私有化 (避免类的外部创建对象)//为了保证这个类只能造一个对象而造对象需要使用到构造器那么在这个类外面就不能让它随便调用构造器private Bank(){ //构造器私有化不对外暴露}
}②在类的内部创建当前类的实例 (一个就可以了)
class Bank{ //假设这个银行只有一个实例中国人民银行//1.类的构造器私有化 (避免类的外部创建对象)//为了保证这个类只能造一个对象而造对象需要使用到构造器那么在这个类外面就不能让它随便调用构造器private Bank(){ //构造器私有化不对外暴露}//2.在类的内部创建当前类的实例 (一个就可以了)private Bank instancenew Bank(); //可以看作当前类的一个属性 (是当前类类型的)不需要放到方法里面习惯将它私有化}③提供私有属性的get方法
类的外部想用这个对象但是对象被私有化了外部无法调用所以要有方法提供
class Bank{ //假设这个银行只有一个实例中国人民银行//1.类的构造器私有化 (避免类的外部创建对象)//为了保证这个类只能造一个对象而造对象需要使用到构造器那么在这个类外面就不能让它随便调用构造器private Bank(){ //构造器私有化不对外暴露}//2.在类的内部创建当前类的实例 (一个就可以了)private Bank instancenew Bank(); //可以看作当前类的一个属性 (是当前类类型的)不需要放到方法里面习惯将它私有化//3.提供私有属性的get方法//类的外部想用这个对象但是对象被私有化了外部无法调用所以要有方法提供public Bank getInstance(){return instance; //在方法里面将造好的对象返回}
}使用getXxx()方法获取当前类的实例必须声明为static的。
通过方法返回当前类的实例那么这个getInstance方法谁来调呢
现在只能拿“对象”来调用这个方法才能拿到getInstance方法来获取此对象。(此时在类外部需要一个对象但是无法通过构造器来创建只能通过getInstance方法来获取一个对象但是这个方法也需要通过对象才能调用而对象需要通过这个方法来获取绕进去了…)
要想调用getInstance方法来获取对象肯定不能拿对象去调用只能通过类来调用那就意味着getInstance方法需要静态化。
public static Bank getInstance(){return instance; //在方法里面将造好的对象返回
}④属性设置为static
上一步将方法声明为static之后会发现报错如下 这是因为静态方法中只能调用静态属性或方法。
所以instance也必须静态化如下
private static Bank instancenew Bank();目前整体的Bank类如下
class Bank{ //假设这个银行只有一个实例中国人民银行//1.类的构造器私有化 (避免类的外部创建对象)//为了保证这个类只能造一个对象而造对象需要使用到构造器那么在这个类外面就不能让它随便调用构造器private Bank(){ //构造器私有化不对外暴露}//2.在类的内部创建当前类的实例 (一个就可以了)//4.此属性也必须声明为static的private static Bank instancenew Bank(); //可以看作当前类的一个属性 (是当前类类型的)不需要放到方法里面习惯将它私有化//3.使用getXxx()方法获取当前类的实例必须声明为static的//类的外部想用这个对象但是对象被私有化了外部无法调用所以要有方法提供public static Bank getInstance(){return instance; //在方法里面将造好的对象返回}
}④测试
使用当前类的唯一实例。
package yuyi04;/*** ClassName: BankTest* Package: yuyi04* Description:** Author 雨翼轻尘* Create 2023/11/17 0017 8:43*/
public class BankTest {public static void main(String[] args) {//使用当前类的唯一实例Bank bank1Bank.getInstance();//再通过getInstance方法获取另外一个所谓的实例其实和上面的实例指向同一个Bank bank2Bank.getInstance();//测试System.out.println(bank1bank2);}
}class Bank{ //假设这个银行只有一个实例中国人民银行//1.类的构造器私有化 (避免类的外部创建对象)//为了保证这个类只能造一个对象而造对象需要使用到构造器那么在这个类外面就不能让它随便调用构造器private Bank(){ //构造器私有化不对外暴露}//2.在类的内部创建当前类的实例 (一个就可以了)//4.此属性也必须声明为static的private static Bank instancenew Bank(); //可以看作当前类的一个属性 (是当前类类型的)不需要放到方法里面习惯将它私有化//3.使用getXxx()方法获取当前类的实例必须声明为static的//类的外部想用这个对象但是对象被私有化了外部无法调用所以要有方法提供public static Bank getInstance(){return instance; //在方法里面将造好的对象返回}
}输出结果 2. 懒汉式
class Singleton {// 1.私有化构造器private Singleton() {}// 2.内部提供一个当前类的实例// 4.此实例也必须静态化private static Singleton single;// 3.提供公共的静态的方法返回当前类的对象public static Singleton getInstance() {if(single null) {single new Singleton();}return single;}
}【举例】
场景GirlFriend只能有一个实例。
package yuyi04;/*** ClassName: GirlFriend* Package: yuyi04* Description:** Author 雨翼轻尘* Create 2023/11/17 0017 9:24*/
public class GirlFriendTest {public static void main(String[] args) {}
}class GirlFriend{}①**类的构造器私有化 **
class GirlFriend{//1.类的构造器私有化 private GirlFriend(){}
}②声明当前类的实例作为一个属性出现。
这时候并没有创建这个对象。
class GirlFriend{//1.类的构造器私有化private GirlFriend(){}//2.声明当前类的实例作为一个属性出现//和刚才一样外边不能造对象了里边就得造。里面造和上一种方法的区别就在于这里只是做了一个声明。private GirlFriend instancenull; //右边在赋值的时候赋值了一个null若是不写本身也是null
}③通过getXxx()方法获取当前类的实例如果未创建对象则在方法内部进行创建。
通过get方法去调用的时候发现没有实例化就帮忙造一下。
class GirlFriend{//1.类的构造器私有化private GirlFriend(){}//2.声明当前类的实例作为一个属性出现//和刚才一样外边不能造对象了里边就得造。里面造和上一种方法的区别就在于这里只是做了一个声明。private GirlFriend instancenull; //右边在赋值的时候赋值了一个null若是不写本身也是null//3.通过getXxx()方法获取当前类的实例如果未创建对象则在方法内部进行创建/*public GirlFriend getInstance(){if(instancenull){ //若此时没有实例化就实例化一下instancenew GirlFriend();return instance; //创建好实例之后返回即可}else{ //若之前已经创建好对象了直接return就好return instance;}}*/public GirlFriend getInstance(){if(instancenull){ //若此时没有实例化就实例化一下instancenew GirlFriend();}//若发现没有实例化就进入if创建好之后返回即可若发现已经有实例了不执行if直接return即可return instance;}
}这里优化一下如下
④静态化属性和方法
和饿汉式一样getInstance方法需要通过类来调用所以这里也需要加上static。如下
public static GirlFriend getInstance(){if(instancenull){ //若此时没有实例化就实例化一下instancenew GirlFriend();}//若发现没有实例化就进入if创建好之后返回即可若发现已经有实例了不执行if直接return即可return instance;
}然后静态方法里面只能调静态的所以instance也要加上static。如下
private static GirlFriend instancenull;现在整体的GirlFriend如下
class GirlFriend{//1.类的构造器私有化private GirlFriend(){}//2.声明当前类的实例作为一个属性出现//4.此属性也必须声明为static的private static GirlFriend instancenull; //右边在赋值的时候赋值了一个null若是不写本身也是null//3.通过getXxx()方法获取当前类的实例如果未创建对象则在方法内部进行创建public static GirlFriend getInstance(){if(instancenull){ //若此时没有实例化就实例化一下instancenew GirlFriend();}//若发现没有实例化就进入if创建好之后返回即可若发现已经有实例了不执行if直接return即可return instance;}
}3. 饿汉式 vs 懒汉式
饿汉式
特点立即加载即在使用类的时候已经将对象创建完毕。优点实现起来简单没有多线程安全问题。缺点当类被加载的时候会初始化static的实例静态变量被创建并分配内存空间从这以后这个static的实例便一直占着这块内存直到类被卸载时静态变量被摧毁并释放所占有的内存。因此在某些特定条件下会耗费内存。
懒汉式
特点延迟加载即在调用静态方法时实例才被创建。优点实现起来比较简单当类被加载的时候static的实例未被创建并分配内存空间当静态方法第一次被调用时初始化实例变量并分配内存因此在某些特定条件下会节约内存。缺点在多线程环境中这种实现方法是完全错误的线程不安全根本不能保证单例的唯一性。 说明在多线程章节会将懒汉式改造成线程安全的模式。
【举例】
还是拿上面两个例子作比较如下这里过滤掉属性了针对当前创建的实例没有任何属性它不属于单例模式的核心问题这里就过滤掉了 “饿汉式”一上来就把对象创建好了立即加载静态声明的变量随着类的加载而加载比较早得出现在内存当中需要用得时候直接拿来用同样随着类的消亡而消亡其实并不会轻易卸载类类都加载到方法区内GC回收方法区的频率非常低此时试图卸载一个类也非常困难因为这个类可能会在任意地方被使用包括被类的加载器所引用类的加载器不消亡它也不会消亡同样静态变量也消除不了所以在内存中占用时间就会很长。
“懒汉式”一上来没有创建当需要的时候才创建延时加载。
从内存节省的角度来说“懒汉式”比较好“饿汉式”实例的生命周期有点长。
之前说过的“内存泄露”-- 本身是个垃圾但是GC还没有帮我们回收。在一定程度上来说有的变量也谈不上泄露但是它的生命周期特别长使用的时间又特别短多余的时间不想要可以回收掉但是它是静态的导致生命周期很长却没有办法回收一定程度上也可以认为是泄露生命周期过长超出了使用的范围。 【对比两种模式】特点、优缺点
特点 饿汉式“立即加载”随着类的加载当前的唯一实例就创建了。懒汉式“延迟加载”在需要使用的时候进行创建。 优缺点 饿汉式优点写法简单由于内存中较早加载使用更方便、更快。是线程安全的。 缺点内存中占用时间较长。懒汉式缺点线程不安全 有可能会创建好几次对象放到多线程章节时解决优点在需要的时候进行创建节省内存空间。
5 单例模式的优点及应用场景
由于单例模式只生成一个实例减少了系统性能开销当一个对象的产生需要比较多的资源时如读取配置、产生其他依赖对象时则可以通过在应用启动时直接产生一个单例对象然后永久驻留内存的方式来解决。
举例
Java中有一个类叫Runtime运行时环境单例设计模式–饿汉式如下 应用场景
Windows的Task Manager (任务管理器)就是很典型的单例模式 。Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中回收站一直维护着仅有的一个实例。Application 也是单例的典型应用。应用程序的日志应用一般都使用单例模式实现这一般是由于共享的日志文件一直处于打开状态因为只 能有一个实例去操作否则内容不好追加。数据库连接池的设计一般也是采用单例模式因为数据库连接是一种数据库资源。
二、理解main方法的语法
1main()方法的剖析
public static void main(String args[]){}理解1看做是一个普通的静态方法。
理解2看做是程序的入口格式是固定的。
解释
public–此方法权限很大在整个项目中都能看得到。
static–静态的随着类的加载而加载。main方法是程序的入口不能说一上来就造一个本类的对象若是造对象才能掉方法但是造对象的方法也得在程序入口里面做卡死了。所以这个时候方法不能拿对象去调只能拿类去调所以只能是static的。
void–这个方法执行完也不需要返回也没有可以返回的结构了已经是最基础的方法了。
main–这个方法比较特别是程序的入口所以写成main表示入口的意思。
由于JVM需要调用类的main()方法所以该方法的访问权限必须是public又因为JVM在执行main()方法时不必创建对象所以该方法必须是static的该方法接收一个String类型的数组参数该数组中保存执行Java命令时传递给所运行的类的参数。
又因为main() 方法是静态的我们不能直接访问该类中的非静态成员必须创建该类的一个实例对象后才能通过这个对象去访问类中的非静态成员这种情况我们在之前的例子中多次碰到。
【举例】
package yuyi04;/*** ClassName: MainTest* Package: yuyi04* Description:** Author 雨翼轻尘* Create 2023/11/18 0018 20:55*/
public class MainTest {public static void main(String[] args) { //程序的入口//造一个String类型的数组String[] arrnew String[]{AA,BB,CC};//通过Main类来调用此类中的静态方法main()Main.main(arr);}
}class Main{public static void main(String[] args) { //看作是普通的静态方法//把参数对应的数组遍历一下System.out.println(Main的main()的调用);for (int i 0; i args.length; i) {System.out.println(args[i]);}}
}输出结果 2与控制台交互
可以发现main方法带了一个形参String args[]到目前为止好像没有用过它有啥用呢
如何从键盘获取数据 方式1使用Scanner传的是各种类型 方式2使用main()的形参进行传值。只能传递String类型 1.举例1
先写一段代码。
【MainDemo.java】
package yuyi04;/*** ClassName: MainDemo* Package: yuyi04* Description:** Author 雨翼轻尘* Create 2023/11/19 0019 7:38*/
public class MainDemo {public static void main(String[] args) { //当我们调用main方法时传递了一个String数组for (int i 0; i args.length; i) { //遍历打印System.out.println(hello:args[i]);}}
}1.1 方式一、命令行
先将文件【MainDemo.java】复制到一个文件夹中比如D盘 命令行的时候没有包的概念记得将第一行导包注释掉如下 记得将文件的字符集改为“ANSI”因为黑窗口的字符集默认GBK如下 改为ANSI才不会乱码 执行文件 由于代码没有输入任何数据所以args.length是0就没有任何执行效果啦。
那如何传呢
在写完类名的时候再写一个空格后边就可以输入数据了第一个要加双引号后边可以不用中间用空格隔开注意一定要是英文格式下。比如java MainDemo Tom Jarry 89 true回车之后便可输出如下 相当于args数组的长度是4依次遍历了它的元素。从控制台获取String类型的数据
在代码层面可以把89转化为int类型把true转化为boolean类型。讲包装类的时候再说这个问题
1.2 方法二、编译器
上面演示了命令行的方式那么在idea编译器中如何体现传值呢
先配置一下。
“运行”–“编辑配置” 可以看到如下信息 找到这个地方点击它 然后输入“MainDemo”选中这个文件 现在就可以在这个地方输入了 比如中间用空格隔开 回到编译器中再次Run可以发现刚才的数据输出了 其实还有其他的方法这里做了解就好不必追究。 2.举例2
代码部分
public class CommandPara {public static void main(String[] args) {for (int i 0; i args.length; i) {System.out.println(args[ i ] args[i]);}}
}//运行程序CommandPara.java
java CommandPara Tom Jerry ShkstartIDEA工具
1配置运行参数 2运行程序 输出
//输出结果
args[0] Tom
args[1] Jerry
args[2] Shkstart3笔试题
如下
//此处Something类的文件名叫OtherThing.java
class Something {public static void main(String[] something_to_do) { System.out.println(Do something ...);}
}//上述程序是否可以正常编译、运行 可以