面向对象(高级)
1.1🌠类变量的定义
先看这段代码
public class ChildGame {
public static void main(String[] args) {
Child jack = new Child("jack");
Child tom = new Child("tom");
Child marry = new Child("marry");
jack.join();
jack.count++;
tom.join();
tom.count++;
marry.join();
marry.count++;
System.out.println("共有"+Child.count+"名小孩加入了游戏");
System.out.println(jack.count);
System.out.println(tom.count);
System.out.println(marry.count);
}
}
class Child{
private String name;
public static int count = 0;
public Child(String name) {
this.name = name;
}
public void join(){
System.out.println(name+"加入了游戏...");
}
}
run
解析
当一个类里的成员被static
关键字所修饰时,这就意味着这个类成员会被这个Child类所有实例化的对象所共享
内存分析
解析
先进行类加载,再加载类变量,之后加载Child这个类的信息,然后是默认初始化,接着是显式初始化,最后是构造器初始化,初始化后,child1对象和child2对象都指向方法区里的静态域里的count变量
总结
(1)static变量是在同一个类中被所有实例化的对象所共享
(2)static变量在类加载中就已经生成了
1.2🌭访问类变量
(1).类变量是随着类的加载而加载,不创建对象也可以访问
(2).创建对象来访问
public class VisitStatic {
public static void main(String[] args) {
// 访问类变量
// (1).类变量是随着类的加载而加载,不创建对象也可以访问
System.out.println(A.name);
//System.out.println(A.n); //err
// (2).创建对象来访问
A a = new A();
System.out.println(a.name);
//System.out.println(a.n); //err
}
}
class A{
// 类变量
public static String name = "小明";
// 私有类变量
private static int n = 10;
}
run
1.3🍐类变量细节
(1).类变量是该类的所有对象所共享的,而实例变量是每个对象独享的
(2).static变量是叫类变量或静态变量,否则称为实例变量/普通变量/非静态变量
(3).类变量可以通过类名.成员名或对象.成员名访问,而普通变量只能通过对象.成员名访问。(前提是满足访问修饰符的访问权限)
(4).类变量是在类加载时就初始化了,在没有创建对象之前,类加载了,就可以使用类变量了
(5).类变量的生命周期是随着类的加载开始随着类消亡而消亡
public class StaticDetail {
public static void main(String[] args) {
B b = new B();
//System.out.println(B.n1);
System.out.println(B.n2);
//静态变量是类加载的时候,就创建了,所以我们没有创建对象实例
//也可以通过类名.类变量名来访问
System.out.println(C.address);
}
}
class B {
public int n1 = 100;
public static int n2 = 200;
}
class C {
public static String address = "北京";
}
1.4🍷类变量应用场景
使用场景
如果在方法中不涉及和对象有关的成员,则可以将方法设计成静态方法提高开发效率
System.out.println("9的开平方结果:"+Math.sqrt(9));
System.out.println(MyTools.sum(10,20));
class MyTools{
public static double sum(int n1,int n2){
return n1+n2;
}
}
通过上面的例子不难看出,不用创建对象就能调用方法,实在是太裤辣!!!
1.5🍼类方法细节
(1).类方法中不能使用this和super这种和对象有关的关键字
(2).普通方法中可以访问静态方法和静态变量
(3).静态方法只能访问静态方法和静态变量
public class Test {
public static void main(String[] args) {
D.hi();//ok
//非静态方法,不能通过类名调用
//D.say();, 错误,需要先创建对象,再调用
new D().say();//可以
}
}
class D {
private int n1 = 100;
private static int n2 = 200;
//非静态方法,普通方法
public void say() {
}
//静态方法,类方法
public static void hi() {
//类方法中不允许使用和对象有关的关键字,
//比如this和super。普通方法(成员方法)可以。
// System.out.println(this.n1); // err
}
//静态方法只能访问静态成员.
public static void hello() {
System.out.println(n2);
System.out.println(D.n2);
//System.out.println(this.n2);不能使用
hi();//OK
//say();//错误
}
//非静态方法可以访问 静态成员和非静态成员
public void ok() {
//非静态成员
System.out.println(n1);
say();
//静态成员
System.out.println(n2);
hello();
}
}
多说不练假把式
1.6🌽类方法练习
class Test {
static int count = 9;
public void count() {
System.out.println("count=" + (count++));
}
public static void main(String args[]) {
new Test().count();
new Test().count();
System.out.println(Test.count);
}
}
run
9 、10 、 11
解析
静态变量随着类加载而加载,随着类结束而消亡
class Person {
private int id;
private static int total = 0;
public static int getTotalPerson() {
//id++;//错误, 注销
return total;
}
public Person() {//构造器
total++; //total = 1
id = total;//id = 1
}
}
class TestPerson {
public static void main(String[] args) {
System.out.println("Number of total is " +Person.getTotalPerson()); //0
Person p1 = new Person();
System.out.println( "Number of total is "+ Person.getTotalPerson()); //1
}
}
run
0、1
class Person {
private int id;
private static int total = 0;
public static void setTotalPerson(int total){
// this.total = total;//错误,因为在static方法中,不可以使用this 关键字
Person.total = total;
}
public Person() {//构造器
total++;
id = total;
}
//编写一个方法,输出total的值
public static void m() {
System.out.println("total的值=" + total);
}
}
class TestPerson {
public static void main(String[] args) {
Person.setTotalPerson(3);
new Person();
Person.m();
}
}
run
4
2.1🤗详解main方法
public static void main(String[] args){}
1.main方法是jvm虚拟机调用
2.jvm虚拟机需要调用类的main方法,所以该方法的访问权限必须是public
3.jvm虚拟机在执行main方法不需要创建对象,所以是static
4.可以接收String类型数组参数,该数组中保存java命令时所传递的参数
5.java 执行程序 参数1 参数2 参数3 …
2.2🍏main方法注意事项
public class Main01 {
private static int n1;
private static void m1(){}
private int n2;
private void m2(){}
public static void main(String[] args) {
// main方法本身就是静态方法
// (1)静态方法只能包含静态成员
m1();
System.out.println(n1);
// (2)静态方法只能包含普通成员
// m2(); // err
// System.out.println(n2); // err
// (3)如果静态方法非要访问普通成员,必须实例化一个对象
Main01 main01 = new Main01();
main01.m2();
System.out.println(main01.n2);
}
}
2.3🍇main方法中的String数组传参
注意要点击右下角的应用
也是成功运行!
3.1🍍代码块的定义
先看一段代码
public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie("你好,李焕英");
System.out.println("===============");
Movie movie2 = new Movie("唐探3", 100, "陈思诚");
}
}
class Movie {
private String name;
private double price;
private String director;
//3个构造器 -》重载
//(1) 下面的三个构造器都有相同的语句
//(2) 这样代码看起来比较冗余
//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可
//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容
//(5) 代码块调用的顺序优先于构造器..
{
System.out.println("电影屏幕打开...");
System.out.println("广告开始...");
System.out.println("电影正式开始...");
};
public Movie(String name) {
System.out.println("Movie(String name) 被调用...");
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
System.out.println("Movie(String name, double price, String director) 被调用...");
this.name = name;
this.price = price;
this.director = director;
}
}
run
总结
如果构造器中有重复的语句,可以使用代码块,减少代码冗余
3.2🍈代码块细节
在谈代码块细节之前大家需要知道类在什么时候会被加载
(1).创建对象实例时
public class CodeBlockDetail01 {
public static void main(String[] args) {
BB bb = new BB();
}
}
class BB {
//静态代码块
static {
System.out.println("BB 的静态代码1被执行...");//1
}
}
(2).子类对象实例化时,父类也会被加载,而且,父类先被加载,子类后被加载
AA aa2 = new AA();
class BB {
//静态代码块
static {
System.out.println("BB 的静态代码1被执行...");//1
}
}
class AA extends BB {
//静态代码块
static {
System.out.println("AA 的静态代码1被执行...");//2
}
}
(3).使用类的静态变量时
System.out.println(Cat.n1);
class Animal {
//静态代码块
static {
System.out.println("Animal 的静态代码1被执行...");//
}
}
class Cat extends Animal {
public static int n1 = 999;//静态属性
//静态代码块
static {
System.out.println("Cat 的静态代码1被执行...");//
}
}
可以看到,执行顺序是父类先加载执行父类的代码块,然后是子类的静态代码块,最后是子类的静态变量
(4).static代码块,是在类加载时,执行的,而且只会执行一次.
DD dd = new DD();
DD dd1 = new DD();
}
}
class DD {
//静态代码块
static {
System.out.println("DD 的静态代码1被执行...");//
}
}
(5).普通的代码块,在创建对象实例时,会被隐式的调用。
被创建一次,就会调用一次。
如果只是使用类的静态成员时,普通代码块并不会执行
DD dd = new DD();
DD dd1 = new DD();
System.out.println(DD.n1);//8888, 静态模块块一定会执行
class DD {
public static int n1 = 8888;//静态属性
//静态代码块
static {
System.out.println("DD 的静态代码1被执行...");//
}
//普通代码块, 在new 对象时,被调用,而且是每创建一个对象,就调用一次
//可以这样简单的,理解 普通代码块是构造器的补充
{
System.out.println("DD 的普通代码块...");
}
}
总结
(1).只有在创建对象时,普通构造器才会调用,调用静态成员时不会被调用
(2).创建对象实例和调用静态成员时静态代码块会被执行,静态代码块只会执行1次,还要注意类的3个加载方式…
代码块在一个类中的执行顺序
(1)如果有多个静态代码块和多个静态变量初始化,就看他们定义的顺序
(2)如果有多个普通代码块和多个普通变量初始化,就看他们定义的顺序
(3)最后看构造器
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();// (1) A 静态代码块01 (2) getN1被调用...(3)A 普通代码块01(4)getN2被调用...(5)A() 构造器被调用
}
}
class A {
//静态属性的初始化
private static int n1 = getN1();
static { //静态代码块
System.out.println("A 静态代码块01");
}
public static int getN1() {
System.out.println("getN1被调用...");
return 100;
}
//无参构造器
public A() {
System.out.println("A() 构造器被调用");
}
private int n2 = getN2();//普通属性的初始化
{ //普通代码块
System.out.println("A 普通代码块01");
}
public int getN2() { //普通方法/非静态方法
System.out.println("getN2被调用...");
return 200;
}
}
构造器中隐含着super和调用普通代码块
public class CodeBlockDetail03 {
public static void main(String[] args) {
new BBB();//(1)AAA的普通代码块(2)AAA() 构造器被调用(3)BBB的普通代码块(4)BBB() 构造器被调用
}
}
class AAA { //父类Object
{
System.out.println("AAA的普通代码块");
}
public AAA() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println("AAA() 构造器被调用....");
}
}
class BBB extends AAA {
{
System.out.println("BBB的普通代码块...");
}
public BBB() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println("BBB() 构造器被调用....");
}
}
- 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 父类普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 父类的构造方法
- 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 子类的构造方法
package codeblock_03;
public class CodeBlockDetail04 {
public static void main(String[] args) {
//(1) 进行类的加载
//1.1 先加载 父类 A02 1.2 再加载 B02
//(2) 创建对象
//2.1 从子类的构造器开始
new B02();//对象
}
}
class A02 { //父类
private static int n1 = getVal01();
static {
System.out.println("A02的一个静态代码块..");//(2)
}
{
System.out.println("A02的第一个普通代码块..");//(5)
}
public int n3 = getVal02();//普通属性的初始化
public static int getVal01() {
System.out.println("getVal01");//(1)
return 10;
}
public int getVal02() {
System.out.println("getVal02");//(6)
return 10;
}
public A02() {//构造器
//隐藏
//super()
//普通代码和普通属性的初始化......
System.out.println("A02的构造器");//(7)
}
}
class B02 extends A02 { //
private static int n3 = getVal03();
static {
System.out.println("B02的一个静态代码块..");//(4)
}
public int n5 = getVal04();
{
System.out.println("B02的第一个普通代码块..");//(9)
}
public static int getVal03() {
System.out.println("getVal03");//(3)
return 10;
}
public int getVal04() {
System.out.println("getVal04");//(8)
return 10;
}
public B02() {//构造器
//隐藏了
//super()
//普通代码块和普通属性的初始化...
System.out.println("B02的构造器");//(10)
}
}
1.静态代码块只能调用静态成员
2.普通代码块可以调用所有成员
public class CodeBlockDetail05 {
public static void main(String[] args) {
new C02();
}
}
class C02 {
private int n1 = 100;
private static int n2 = 200;
private void m1() {
}
private static void m2() {
}
static {
//静态代码块,只能调用静态成员
//System.out.println(n1);错误
System.out.println(n2);//ok
//m1();//错误
m2();
}
{
//普通代码块,可以使用任意成员
System.out.println(n1);
System.out.println(n2);//ok
m1();
m2();
}
}
3.3🍒代码块练习题
public class CodeBlockExercise01 {
public static void main(String[] args) {
System.out.println("total = "+ Person.total); //100
System.out.println("total = "+ Person.total); //100
}
}
class Person {
public static int total;//静态变量
static {//静态代码块
total = 100;
System.out.println("in static block!");//(1)
}
}
public class CodeBlockExercise02 {
}
class Sample
{
Sample(String s)
{
System.out.println(s);
}
Sample()
{
System.out.println("Sample默认构造函数被调用");
}
}
class Test{
Sample sam1=new Sample("sam1成员初始化");//
static Sample sam=new Sample("静态成员sam初始化 ");//
static{
System.out.println("static块执行");//
if(sam==null)System.out.println("sam is null");
}
Test()//构造器
{
System.out.println("Test默认构造函数被调用");//
}
//主方法
public static void main(String str[])
{
Test a=new Test();//无参构造器
}
}