Vector v = new Vector();
Object obj = v.elementAt(i); //v.elementAt()返回的是一个Object对象
//Double D = (Double)obj;
//double d = D;
//以上把obj向下转型成Double再拆箱成double可以直接转成一个式子:
double d = (double)obj;
数组也继承了Object类,可以使用equas()和toString()等方法。所以可以认为数组是一种特殊的类
关键字native:到此接下来执行的就是底层的C/C++的代码了
可以用来修饰方法的关键字:static、final、abstract、native
多态存在很大部分是因为参数传递,形参是父类,实参是子类,形成多态,方便代码结构的扩展和整洁。
可以直接获取现在的月份,操作类似于Scanner:
导包:import java.util.Calendar;
Calendar c = Calendar.getInstance();//Calendar是单例模式,不能new出一个对象
//因为单例模式的构造器是private的,因此只能通过类调用静态方法getInstance()来获取对象
int month = c.get(Calendar.MONTH);//1月是0,二月是1......
static:静态的
引入:
某些特定属性可以在内存中只有一份,属于所有对象共有,不用再特定给每个对象进行定义,比如中国人的国家名称,这时候就需要static。
static可以修饰属性、方法、代码块、内部类
一、static修饰属性:属性分为静态属性(类变量)和非静态属性(实例变量)
1.非静态变量:当创建了类的多个对象,每个对象都拥有一套非静态属性,当修改一个对象中的非静态属性时,不会导致其他对象中的属性改变。
2.静态变量:创建了多个对象,多个对象共享同一个静态变量,当修改一个对象的静态变量时,其他对象调用此静态变量时,都是修改过的。
3.静态变量随着类的加载而加载,所以静态变量的加载早于对象的创建,并且类只会加载一次,所以静态变量在内存中也只会存在一份:存在方法区的静态域中。可以通过“类.静态变量”的方式进行调用
4.静态属性举例:System.out;Math.PI
5.内存解析:
二、static修饰方法:静态方法
1.静态方法随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
2.静态方法中:只能调用静态属性和静态方法
非静态方法中:既可以调用非静态的方法和属性,也可以调用静态的方法和属性
3.在静态方法内,不能使用this和super关键字
三、开发中如何确定一个属性是否要声明为static:
1.属性是可以被多个对象所共享的,不会随着对象的不同而不同
2.类中的常量一般声明为static
四、开发中如何确定一个方法是否要声明为static:
1.操作静态属性的set、get方法或包含静态属性的方法通常设为static的
2.工具类中的方法,习惯上声明为static的(因为没必要去创建对象),比如:Math,Arrays,Collections
static使用举例:
class Person{
private int id;
//要求创建person对象时,id从201801开始,每创建一个对象,id变为201802,201803......
//这时就需要定义一个static的init,每调用一次构造器就+1
private static int init = 201801;
public Person() {
id = init++;
}
}
单例设计模式
设计模式
设计模式是在大量的实践中总结的代码结构、编程风格、以及解决问题的思考方式。类似于套路,或者说不同棋局的棋谱,可以免去我们思考,直接按照套路去编程。有23种经典的设计模式。
单例设计模式(Singleton):采取一定的方法保证这个对象在虚拟机中只能产生一个对象。
必须使类的构造器权限是private,这样就不能在类的外部new出对象了,只能在类的内部产生对象。为了在类的外部得到类内部的对象,需要调用类的某个静态方法以返回类内部创建的对象,由于静态方法只能访问类中的静态变量,所以类中的属性必须都是静态属性。
一、具体实现的两个方法:
1.饿汉式:
//饿汉式
class Person{
//1.私有化构造器
private Person() {
}
//2.类内部创建对象(static)
private static Person p = new Person();
//3.提供public、static的方法返回类的内部对象
public static Person getInstance() {
return p;
}
}
2.懒汉式:
// 懒汉式
class Person {
// 1.私有化构造器
private Person() {
}
// 2.声明对象(static),但不初始化
private static Person p = null;
// 3.提供public、static的方法返回当前对象
public static Person getInstance() {
if (p == null) {// 判断当年p为空时即还没有创建对象时,在创建对象
p = new Person();
}
return p;
}
}
或者不提供返回类的方法,直接public static final Person p = new Person();加final是为了防止把p修改成null,这样就会把p释放了。
Person p1 = Person.p;
Person p2 = Person.p;//p2和p1是一个对象
Person.p = null;//p被释放了
Person p3 = Person.p;//此时p3和p1、p2就不是一个对象了
二、区分饿汉式和懒汉式
饿汉式:坏处:对象加载时间过长。好处:线程是安全的
懒汉式:好处:延迟对象的创建,节省内存。坏处:目前的写法线程不安全(具体修改见多线程那一章)
三、单例模式优点:
单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。如java.lang.Runtime
四、单例模式的应用场景:
网站计数器,应用程序的日志,数据库连接池,读取配置文件的类,windows的任务管理器和回收站等。
main方法
1.程序的入口
2.是一个静态方法
3.main方法要求权限是public,这样在虚拟机中才方便找到
4.main方法不需要返回类型,所以是void
5.main方法有参数列表(String[] args)是一个String型的数组,所以main方法可以作为我们与控制台交互的方式(之前交互的方式是Scanner)(具体方法:先编译一下,在解释字节码的时候进行交互,交互完运行程序即可)
代码块
代码块或称为初始化块(block)
形式:在类中直接用大括号{ },代码块只能用static修饰,其他的关键字都不能修饰代码块
一、代码块的作用:用来初始化类、对象
二、代码块分为:静态代码块、非静态代码块
静态代码块:
1.内部可以有输出语句
static{
System.out.println("static block");
}
2.随着类的加载而执行;静态方法是随着类的加载而加载,不执行,当“类.静态方法”时才执行
3.静态代码块只执行一次
4.作用:对类中的静态属性就行初始化
5.如果一个类中定义了多个静态代码块,则按照声明的先后顺序进行执行
6.静态代码块的执行优先于非静态代码块的执行
7.静态代码块只能调用静态结构
非静态代码块:
1.内部可以有输出语句
{
System.out.println("block");
}
2.随着对象的加载而执行;非静态方法是随着对象的加载而加载,不执行
3.每创建一个对象,就执行一次非静态代码块
4.作用:可以在创建对象时,对对象的属性就行初始化
5.如果一个类中定义了多个非静态代码块,则按照声明的先后顺序进行执行
6.非静态代码块既可以调用静态结构,也可以调用非静态结构
代码块的执行先于构造器,原因:new一个对象本质是调用类的构造器,但是在调用构造器时得先加载类,加载类的时候静态代码块就已经执行了,而非静态代码块在加载对象时也执行了,所以构造器执行之前得先执行代码块。
对属性赋值的位置:
1.默认初始化
2.显式初始化
3.构造器初始化
4.有了对象后,通过“对象.属性”赋值
5.代码块中赋值
执行的顺序:1-> 2/5-> 3-> 4(2和5看声明的顺序,如果先写int age = 10;再写代码块{age = 11;}则先执行2再执行5;如果先写代码块{age = 11;},再写int age = 10;则先5后2)
final:最终的
一、final可以修饰类、方法、变量
二、final修饰类:最终的类,此类不能被其他类继承。比如:String类,System类,StringBuffer类
三、final修饰方法:最终的方法,此方法不可以被重写。比如:Object类中的getClass()方法
四、修饰变量:最终的变量,此变量成为一个常量。类似于C/C++的const
1.final修饰属性:可以赋值的位置:显式初始化、代码块中初始化、构造器中初始化。不能通过set方法或者“对象.属性”进行赋值
class A{
final int A1 = 0;//显式初始化
final int A2;
final int A3;
{
A2 = 1;//代码块中初始化
}
A(int num){
A3 = num;//构造器中初始化
}
}
2.final修饰局部变量:是一个常量,不能修改。当final修饰的是形参时,表明此形参是常量,当调用此方法时,给常量赋一个实参,一旦赋值后,只能在方法体内使用形参,不能修改形参。
class Person{public int i;}
public void add(final Person p) {
p.i++;//这个没问题,因为final修饰的是p不是i,p的地址没变就可以,i变不变都行。若是在方法中有p=new Person();则出错
}
五、static final修饰属性:全局常量。static final也可以修饰方法,不过见的少。
abstract:抽象的
一、abstract可以用来修饰类和方法
二、abstract修饰类:抽象类
1.此类不能实例化
2.抽象类中一定有构造器,便于子类实例化时调用(子类的构造器需要调用super();)
3.开发中,都会提供抽象类的子类,让子类对象实例化
三、abstract修饰方法:抽象方法(类似于C++中的虚函数)
1.抽象方法只有方法的声明,没有方法体。
如public abstract void eat();//不用写{},因为没有方法体
2.包含抽象方法的类一定是一个抽象类。(因为抽象方法没有方法体,调用抽象方法是无意义的,所以不能调用抽象方法,所以类必须是抽象类,因为抽象类无法实例化对象,也就无法调用抽象方法了)反之,抽象类中可以没有抽象方法。
3.若子类重写了父类中的所有的抽象方法后,此子类才可以实例化。若子类没有重写父类所有的抽象方法,则此类必须是抽象类,需用abstract进行修饰。
四、注意点
1.abstract不能用来修饰属性、构造器等结构。
2.abstract不能用来修饰私有方法(因为不能被重写),不能修饰静态方法(子父类中的同名同参的静态方法不构成重写,非静态的才算重写),不能修饰final的方法(因为final的方法不能被重写),不能修饰final的类(可以看出final和abstract是不相容的)
抽象类和抽象方法举例:
public abstract class Employee {
private String name;
private int id;
private double salary;
public Employee() {
}
public Employee(String name,int id,double salary) {
this.name=name;
this.id=id;
this.salary=salary;
}
public abstract void work();
}
public class Manager extends Employee{
private double bonus;//奖金
public Manager() {
}
public Manager(String name, int id, double salary, double bonus) {
super(name, id, salary);
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("管理员工");
}
}
public class CommonEmployee extends Employee{
@Override
public void work() {
System.out.println("咱是一线打工人");
}
}
匿名子类的概念
public class EmployeeTest {
public void method(Employee e) {//发生多态
e.work();
}
public static void main(String[] args) {
EmployeeTest et = new EmployeeTest();
Manager m = new Manager();
et.method(m);//非匿名类、非匿名对象
et.method(new Manager());//匿名子类对象
//如果我们需要再声明一个Cleaner子类(继承Employee),并且Cleaner子类只需要new一个对象并当成实参传递
//那么我们就没有必要去再创建一个Cleaner类,然后再new一个对象进行传递。这样太麻烦了
//可以直接使用匿名子类:
Employee eCleaner = new Employee() {
@Override
public void work() {
System.out.println("打扫卫生");
}
};
//首先,eCleaner肯定不是Employee类,因为Employee类是抽象类,不能实例化,然后eCleaner重写了抽象方法
//所以eCleaner肯定是Employee的子类。所以这是一个没有名字的子类,成为匿名子类。匿名子类方便进行一次性的参数传递:
et.method(eCleaner);
}
}
输出:
模板方法设计模式
抽象类体现的是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为
解决的问题:
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变的部分可以抽象出来,供不同子类实现。这就是一种模板模式。
举例:
public abstract class Template {
public void spendTime(){//计算某段代码执行的时间
long start = System.currentTimeMillis();
testCode();
long end = System.currentTimeMillis();
System.out.println("代码执行的时间为"+(end-start));
}
//要测试的代码是可变的,写成抽象方法
public abstract void testCode();
}
class subTemplate extends Template{
//计算输出1000以内的质数的时间
@Override
public void testCode() {
for(int i=2;i<=1000;i++) {
boolean isFlag = true;
for(int j=2;j<=Math.sqrt(i);j++) {
if(i%j==0) {
isFlag = false;
break;
}
}
if(isFlag) {
System.out.println(i);
}
}
}
}
public class TemplateTest {
public static void main(String[] args) {
Template t = new subTemplate();
t.spendTime();
}
}