前言
记录没有条理性,记一些自己没怎么用过,但是比较重要的内容。所以不是那么全面。
因为自己有一些java基础,为秋招准备的。大家看看就好,有错误的地方欢迎指正。、
本节内容:面向对象-下,关键字static,单例模式,final,abstract,interface,代码块,内部类。
一、关键字static
静态的。
可以用来修饰属性,方法,代码块和内部类。
1、修饰属性
希望无论产生多少对象,某些特定的数据在内存空间只有一份。
两个不同对象有各自不同的属性,比如C1对象中的radius和C2对象中的radius属性互无关系,存在不同的空间。而有些属性在对象中共享,成为类属性,同类方法,不用创建对象就可以调用。
- 静态属性:也叫类变量。多个对象共享,当某一个对象修改之时,其他对象看到的是修改过的静态属性。
- 非静态属性:也叫实例变量。每个对象都有各自的,来自于类的非静态属性。你改你的我改我的互不影响。
特性:
- 随着类的加载而加载,先于对象存在。
- 为所有对象共享,可不创建对象直接用类调用。
- 类可以调类变量,不能调实例变量;对象可以调类变量,也可以调实例变量。
内存解析:
2、修饰方法
凡是静态的,都随着类的加载而加载,可以通过“类.静态方法”调用。
- 静态方法中(即类中),只能调用静态的方法和属性,生命周期一致;静态只能调静态
- 非静态方法中(即对象中),既可以调用非静态(对象)的方法和属性,也可以调用静态的方法和属性。
3、注意点
在静态的方法中,不能使用this和super(代表的是本类和父类),用生命周期来理解,静态方法不能被重写。
4、使用场合
静态属性:可以被多个对象共享的,不会随对象不同而不同的。或者,常量。
静态方法:操作静态属性的方法。或者,工具类中的方法:Math.sqrt,Arrays.sort…,Collections,直接用类名调用工具。
5、举例
package com.atguigu.java1;
//static关键字的应用
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle(); //根据下面的构造器,这里自动赋值了id
Circle c2 = new Circle();
Circle c3 = new Circle(3.4);
System.out.println("c1的id:" + c1.getId() );
System.out.println("c2的id:" + c2.getId() );
System.out.println("c3的id:" + c3.getId() );
System.out.println("创建的圆的个数为:" + Circle.getTotal()); //类.静态变量
}
}
class Circle{
private double radius; //不同圆半径不同,所以不用static
private int id; //圆的编号,每个人不同,但是相互之间有++关系,所以有静态的init来负责id赋值
public Circle(){ //构造器一
id = init++; //init是多个对象共享,所以是static,值为1001赋给id,再++
total++; //记录对象-圆的个数
}
public Circle(double radius){ //构造器二
this();
// id = init++;
// total++;
this.radius = radius;
}
private static int total;//记录创建的圆的个数,类自己管理就好,不用给到对象。
private static int init = 1001;//static声明的属性被所有对象所共享,相当于总的管理处
public double findArea(){return 3.14 * radius * radius;}
public double getRadius() {return radius;}
public void setRadius(double radius) {this.radius = radius;}
public int getId() {return id;}
public static int getTotal() { //total是静态变量,所以该方法也是static
return total;
}
}
二、设计模式
1、概念
大量实践中总结和理论化之后的优选的代码结构,编程风格,思考方式。
单例模式:采用方法让整个软件系统中,某个类只存在一个对象实例,且该类只提供一个取得其对象实例的方法。
具体操作:类的构造器权限为private,故只能在类的内部new对象。所以类的外部只能调用类的静态方法来返回类内部创建的这个对象,所以
翻译成人话:即在类外,不能用new某个对象来使用其属性了,只能“类.方法”或者“类.属性”使用其方法。所以,这里的方法必须是静态的,才能“类.方法”,所以该方法中的变量也必须是静态的。
2、实现
饿汉式 vs 懒汉式
package com.atguigu.java2;
public class SingletonTest1 {
public static void main(String[] args) {
// Bank bank1 = new Bank(); 这个时候就没办法new了,因为其构造器为private,现在在类外
// Bank bank2 = new Bank();
//饿汉式
Bank bank1 = Bank.getInstance(); //只能通过bank类中的静态方法来新建对象
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2); //返回true,因为static是共享空间,地址一样(==比较的是地址)
//懒汉式
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1 == order2);
}
}
//饿汉式
class Bank{
//1.私有化类的构造器,构造器不加static
private Bank(){
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的,这里注意前面的private static
private static Bank instance = new Bank(); //上来就new好,饿汉,上来就把事情做完
//Bank instance = new Bank();
//3.提供公共的静态的方法,返回类的对象,类外调用此方法
public static Bank getInstance(){
return instance;
}
}
//懒汉式
class Order{
//1.私有化类的构造器
private Order(){
}
//2.声明当前类对象,没有初始化
//4.此对象也必须声明为static的
private static Order instance = null; //饿汉懒汉以此为区分,这里先不创建,后面需要的再创建
//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
if(instance == null){ //啥时候用啥时候造
instance = new Order();
}
return instance;
}
}
饿汉式:坏:对象加载时间(对象在内存中存在的时间)过长;好:但是线程安全。
懒汉式:好:推迟对象的创建,要用了再造,节省内存空间;坏:但是线程不安全,俩个人同时抢到一张票。到多线程内容时再修改。
3、使用场景
- 网站的计数器,应用程序的日志应用
- 数据库连接池:使用数据库首先需要连接,而这么多连接先连接好,都放在连接池中,这个池子就是单例模式,只有一个
- application进程,任务管理器等
三、main的使用
-
程序的入口,是一个普通的静态方法。
之前的main中调用类中的属性时,需要先新建对象才能调用其属性,因为main是static的,所以只能调用static的属性,所以只需要在之前的属性前加上static。 -
可以作为与控制台交互的方式。 之前:使用Scanner,现在:在eclipse中右键-run as跑一下,再run as-run configuration,找到该类,选择arguments,填入参数,即为输入args到main中。
其中,只有数值型的才能转换为int型。
如何将控制台获取的数据传给形参:String[] args?比如运行时:java 类名 “Tom” “Jerry” “123” “true”
sysout(args[0]);//"Tom"
sysout(args[3]);//"true" -->Boolean.parseBoolean(args[3]);
sysout(args[4]);//报异常
四、代码块
作用:初始化类和对象。要么不加关键词,要加就只有static。
分类:static静态和非静态的。
初始化的顺序:
- 默认初始化(系统给的)
- 显式初始化(类中定义属性时int Id = 3)/ 在代码块中赋值
- 构造器初始化
- 对象.属性或者对象.方法
static{...},静态
{...},非静态
1、静态代码块
- 作用:初始化类的信息,内部可以有输出。随着类的加载并且执行里面的代码,而且只执行一次,跟着类而非对象走。
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。静态代码块的执行要优先于非静态代码块的执行。一般开发中不会写很多的代码块,会合到一起。
- 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构。即静态只能调静态
2、非静态代码块
- 作用:可以在创建对象时,对对象的属性等进行初始化。内部可以有输出语句。随着对象的创建而执行,每创建一个对象,就执行一次非静态代码块
- 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法。(对象可以调用非静态和静态,类无法调非静态,因为只有具体的对象创建出来,才能调用个性化的非静态)
3、 实际应用
//常量池的应用datasource
public class JDBCUtils{
private static DataSource dataSource = null; //常量池类,先是定义为null,需要的时候再创建对象,懒汉式
static{
...
... //准备创建datasource对象所需要的资源
dataSource = 。。。。 //创建对象了
//因为创建这个对象需要做诸多准备工作,这些工作不能作为属性直接放在前面private的前面,所以放在了代码块中,准备好了再创建。
//又因为是静态的代码块,所以只造一次。不管新建了多少对象,只跟着类走。常量池值新建了一次。并且只调用静态的属性
//属性不可以调方法,代码块中可以
}
}
class A{ //类
int a;
a += 1; 或 a = 1;//错误,类中的属性不能这样赋值
int a = 1; //对
int b(){ //方法
}
}
涉及到继承中的代码块,顺序:由父及子,静态现行。静态 > 非静态 > 构造器。
五、关键词final
用于修饰:类,方法,变量
1、final修饰类
此类不能被其他类继承,比如String类,System类,StringBuffer类
2、final修饰方法
此方法不能被重写,比如Object类中的getClass();
final class FinalA{
}
class B extends FinalA{ //报错,final类无法继承
}
class AA{
public final void show(){
}
}
class BB extends AA{
public void show(){ //报错,final方法不可以被重写
}
}
3、final修饰变量:常量。
- 修饰属性:可以考虑赋值的位置,显式初始化,代码块中显式初始化,构造器中初始化
final int WIDTH = 0; final int LEFT; final int RIGHT; { LEFT = 1; } public FinalTest(){ RIGHT = 2; }
- 修饰局部变量(即方法中的):final修饰形参时,表明此形参是个常量,且只能在方法体中使用,且不能重新赋值。
public void show(){ final int NUM = 10;//常量 // NUM += 20; } public void show(final int num){ // num = 20;//编译不通过。在传入形参的时候已经赋值了,不能重新赋值 System.out.println(num); }
- static final修饰属性:全局常量
六、关键字abstract
可以用来修饰类,方法
1、abstract修饰类:抽象类
- 此类不可实例化;一定有构造器,供子类在实例化时调用,开发中会提供抽象类的子类。
- 抽象只是不能实例化,是可以被继承的。
2、abstract修饰方法:抽象方法
- 抽象方法只有方法的声明,没有方法体;
- 包含抽象方法的类,一定是个抽象类。反之,抽象类中可以没有抽象方法。
- 子类重写了父类的所有的抽象方法后,此子类方可实例化。若没有重写父类的全部抽象方法,说明此子类依然是个抽象类,需要前面加上abstract。
public class AbstractTest {
public static void main(String[] args) {
//一旦Person类抽象了,就不可实例化
// Person p1 = new Person();
// p1.eat();
Student s1 = new Student(); //student将所有的抽象方法重写了,所以可以实例化了
s1.eat();
s1.breath();
}
}
abstract class Creature{ //抽象类
public abstract void breath(); //抽象方法breath
}
abstract class Person extends Creature{ //有抽象方法eat,故依然是抽象类
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法:
// public void eat(){
//
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
public void eat(){ //重写直接父类中的抽象方法
System.out.println("学生多吃有营养的食物");
}
@Override
public void breath() { //重写间接父类中华的抽象方法
System.out.println("学生应该呼吸新鲜的没有雾霾的空气");
}
//如此,才可以实例化
}
3、注意点
- 不能用abstract修饰:属性,构造器。因为abstract核心就是不给值,所以属性代码块不能。
- 不能用abstract修饰:私有方法(私有方法本来就不能继承给子类),静态方法(static在内共享区域),final方法final(不能重写)
4、模板方法设计模式
功能内部一部分实现是确定的,一部分是不确定的。这时可以把不确定的部分暴露出去,让子类
七、接口interface
1、定义
- 从几个类中抽取出一些共同的行为特征,他们之间没有is a关系,但是有相同的行为特征。继承:子类 is a 父类,即是不是;接口:能不能。
- 接口的本质是契约,标准,规范。接口与类是并列的两个结构。
- 接口是抽象方法和常量值定义的集合。
2、特点
- 所有成员变量都是public static final修饰,全局常量
- 所有抽象方法都是public abstract修饰的,抽象方法
- 接口中没有构造器,不能实例化
3、使用
- 接口通过让类去实现implements的方式来使用。
如果这个类覆盖了接口中的所有抽象方法,那么这个类可以实例化
如果实现类没有覆盖接口中的所有抽象方法,那么这个类仍然为抽象类,无法实例化。 - java类可以实现多个接口,弥补了java单继承性的局限性。
class AA extends BB implements CC,DD,EE
- 接口和接口之间可以继承,而且可以多继承。
interface CC extends AA,BB
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
// Flyable.MIN_SPEED = 2;
Plane plane = new Plane();
plane.fly();
}
}
interface Flyable{ //接口:能不能
//全局常量
public static final int MAX_SPEED = 7900; //第一宇宙速度
int MIN_SPEED = 1; //省略了public static final
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
//Interfaces cannot have constructors 接口不能有构造器
// public Flyable(){
//
// }
}
interface Attackable{
void attack();
}
class Plane implements Flyable{ //接口flyable的两个方法都被覆盖了,所以Plane类可以实例化
@Override
public void fly() {
System.out.println("通过引擎起飞");
}
@Override
public void stop() {
System.out.println("驾驶员减速停止");
}
}
abstract class Kite implements Flyable{ //没有覆盖flyable的所有方法,所以仍然是抽象类abstract
@Override
public void fly() {
}
}
class Bullet extends Object implements Flyable,Attackable,CC{ //重写了是三个接口的所有方法,所以Bullet可以实例化造对象
@Override
public void attack() {
// TODO Auto-generated method stub
}
@Override
public void fly() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
}
//************************************
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{ //接口继承接口
}
关于接口的多态性
class Computer{
public void transferData(USB usb){//USB usb = new Flash();
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
interface USB{
//常量:定义了长、宽、最大最小的传输速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开启工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
体会:
- 1.接口使用上也满足多态性
- 2.接口,实际上就是定义了一种规范
- 3.开发中,体会面向接口编程!比如数据库,在应用程序中调用的接口都是JDBC定义的接口,不会出现具体某个数据库厂商的API。
4、面向接口编程
- Java8中关于接口的新规范
- 知识点1:接口中定义的静态方法,只能通过接口来调用。
- 知识点2:通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
- 知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>类优先原则
- 知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没重写此方法的情况下,报错。–>接口冲突。这就需要我们必须在实现类中重写此方法
- 知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
- 面试题:
抽象类和接口的异同?
相同点:不能实例化;都可以包含抽象方法的。
不同点:
1)把抽象类和接口(java7,java8,java9)的定义、内部结构解释说明
2)类:单继承性 接口:多继承
类与接口:多实现
八、代理模式
为其他对象提供一种代理以控制对这个对象的访问。
interface NetWork{
public void browse(); //浏览
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
九、工厂模式
-
解决的问题
实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。 -
具体模式
- 简单工厂模式:用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)
- 工厂方法模式:用来生产同一等级结构中的固定产品。(支持增加任意产品)
- 抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
十、内部类(基本不用)
内部类:类的第五个成员
- 定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.
- 内部类的分类:
成员内部类(静态、非静态 ) vs 局部内部类(方法内、代码块内、构造器内) - 成员内部类的理解:
一方面,作为外部类的成员:
- 调用外部类的结构
- 可以被static修饰
- 可以被4种不同的权限修饰
另一方面,作为一个类:
- 类内可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
- 可以被abstract修饰、
成员内部类:
- 如何创建成员内部类的对象?(静态的,非静态的)
//创建静态的Dog内部类的实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
//创建非静态的Bird内部类的实例(非静态的成员内部类):
//Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
- 如何在成员内部类中调用外部类的结构?
class Person{
String name = "小明";
public void eat(){
}
//非静态成员内部类
class Bird{
String name = "杜鹃";
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
//Person.this.eat();
}
}
}
- 局部内部类的使用:
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
- 注意点:
在局部内部类的方法中(比如:show如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。
jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及之后的版本:可以省略final的声明 - 总结:
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:成员内部类:外部类 $ 内部类名.class;局部内部类:外部类 $ 数字内部类名.class
面向对象终于更完了,呼~。一周忙着回家,做项目,没有之前更新的快了。虽然但是感觉自己写过的又忘记了,害。
不经一番寒彻骨,怎得梅花扑鼻香