1 package cn.temptation;
 2
 3 public class Sample01 {
 4     public static void main(String[] args) {
 5         // 继承关系的子类可以重写父类给它的成员方法
 6         // 有时,父类不希望它的成员方法被子类重写(覆盖),对于这种要求,如何处理?
 7         // 答:首先会想到把public 改为 private,但是这样会导致外部无法调用该方法。所以,Java提供了   final 关键字
 8
 9         // final 使用格式:
10         // 修饰符     final   成员方法(...) { ... }
11
12     }
13 }
14
15 //class Father {16     public void show() {17         System.out.println("这是父类的show方法");
18     }
19 //
20 //    public final void show() {
21 //        System.out.println("这是父类的show方法");
22 //    }
23 //}
24 //
25 //class Baby extends Father {
26 //    // 父类的show方法使用final修饰后,子类中就无法再重写show方法了
27 //    // 语法错误:Cannot override the final method from Father
28     public void show() {29         System.out.println("这是子类的show方法");
30     }
31 //}

 1 package cn.temptation;
 2
 3 public class Sample02 {
 4     public static void main(String[] args) {
 5         // final关键字可以用来修饰  成员变量、成员方法     和    类
 6
 7         // final修饰类,该类不能被继承
 8
 9         // final修饰类的理解:断子绝孙
10     }
11 }
12
13 final class Test {
14
15 }
16
17 // Test类使用final修饰后,不能被继承
18 // 语法错误:The type TestEx cannot subclass the final class Test
19 //class TestEx extends Test {
20 //
21 //}

 1 package cn.temptation;
 2
 3 public class Sample03 {
 4     public static void main(String[] args) {
 5         // final修饰成员变量:赋值一次后不能再进行赋值
 6 //        Child child = new Child();
 7 //        child.show();
 8
 9         // 常量:
10         // 1、字面量常量:true、false、123、'a'、"China"
11         // 2、自定义常量:使用final修饰符修饰的成员变量            final int i = 2;
12
13         // 所以,自定义常量一般也使用常量的编码规范:即全部字母均大写,如果是多个单词组成,使用下划线_连接
14     }
15 }
16
17 //class Parent {
18 //    public int i = 2;
19 //    public final int j = 4;
20 //
21 //    // 对于非final修饰的成员变量,不进行初始化赋值,是可以使用其默认值
22 //    public int x;
23 //    // 对于final修饰的成员变量,必须进行初始化赋值
24 //    // 语法错误:The blank final field y may not have been initialized
25     public final int y;
26 //    // 先定义成员变量y,接着进行赋值也是有语法错误
27     y = 123;
28 //
29 //    // 自定义常量一般也使用常量的编码规范:即全部字母均大写,如果是多个单词组成,使用下划线_连接
30 //    public final int K = 100;
31 //    public final boolean CHECK_FLAG = true;
32 //}
33 //
34 //class Child extends Parent {
35 //    public void show() {
36 //        // 下面两组代码效果相同
37         this.i = 3;
38         System.out.println(this.i);
39 //
40 //        super.i = 3;
41 //        System.out.println(super.i);
42 //
43 //        // final修饰的成员变量不能被改变
44 //        // 语法错误:The final field Parent.j cannot be assigned
45         this.j = 5;
46         System.out.println(this.j);
47 //        // 语法错误:The final field Parent.j cannot be assigned
48         super.j = 5;
49         System.out.println(super.j);
50 //    }
51 //}

 1 package cn.temptation;
 2
 3 public class Sample04 {
 4     public static void main(String[] args) {
 5         // final修饰局部变量
 6         // 1、final修饰值类型的局部变量,赋值一次后不能再赋值
 7         // 2、final修饰引用数据类型的局部变量,new过一次后不能再new了,创建过一次引用数据类型对象后就不能再创建了
 8         //        也就是说该局部变量在堆中有一个内存空间后就不能再创建新的内存空间了
 9
10         int i = 2;
11         System.out.println(i);
12         i = 3;
13         System.out.println(i);
14
15         final int j = 4;
16         System.out.println(j);
17         // The final local variable j cannot be assigned. It must be blank and not using a compound assignment
18 //        j = 5;
19 //        System.out.println(j);
20
21         System.out.println("--------------------------------------");
22
23 //        Demo demo = new Demo();
24 //        System.out.println(demo);
25 //        System.out.println(demo.k);
26 //        demo = new Demo();
27 //        demo.k = 88;
28 //        System.out.println(demo);
29 //        System.out.println(demo.k);
30
31         final Demo demoEx = new Demo();
32         System.out.println(demoEx);
33         System.out.println(demoEx.k);
34         // The final local variable demoEx cannot be assigned. It must be blank and not using a compound assignment
35 //        demoEx = new Demo();
36         demoEx.k = 77;
37         System.out.println(demoEx);
38         System.out.println(demoEx.k);
39
40         // 注意:
41         // 使用final修饰的引用数据类型的局部变量虽然不能更改其在堆内存中创建的空间地址,但是其在堆内存中的成员变量的值还是可以修改的
42     }
43 }
44
45 class Demo {
46     int k = 99;
47 }

 1 package cn.temptation;
 2
 3 public class Sample05 {
 4     public static void main(String[] args) {
 5         // 使用final、final static修饰的成员变量  与 构造代码块内外 赋值的问题
 6
 7         TestEx testEx = new TestEx();
 8     }
 9 }
10
11 class TestEx {
12     // 成员变量
13     int i = 2;
14
15     // 语法错误:The blank final field j may not have been initialized
16     final int j;
17
18     final int k = 3;
19
20     final static int m = 4;
21
22     // 语法错误:The blank final field n may not have been initialized
23 //    final static int n;
24
25     final int x = 123;
26
27     final static int y = 987;
28
29     // 构造代码块
30     {
31         System.out.println(i);
32         i = 3;
33         System.out.println(i);
34
35         System.out.println(k);
36
37         // 语法错误:The blank final field j may not have been initialized
38 //        System.out.println(j);
39         // 在构造代码块之前使用final修饰成员变量并不赋值,在构造代码块中进行赋值,语法OK
40         j = 5;
41         System.out.println(j);
42
43         // 在构造代码块之前使用final static修饰成员变量并不赋值,在构造代码块中进行赋值,语法也出错
44         // 语法错误:The final field TestEx.n cannot be assigned
45 //        n = 6;
46 //        System.out.println(n);
47
48         System.out.println(x);
49         // 对于构造代码块之前已经赋值的final修饰的成员变量,在构造代码块中进行赋值,语法也出错
50         // 语法出错:The final field TestEx.x cannot be assigned
51 //        x = 456;
52 //        System.out.println(x);
53
54         System.out.println(y);
55         // 对于构造代码块之前已经赋值的final static修饰的成员变量,在构造代码块中进行赋值,语法也出错
56         // 语法出错:The final field TestEx.y cannot be assigned
57 //        y = 654;
58 //        System.out.println(y);
59     }
60 }

  1 package cn.temptation;
  2
  3 public class Sample06 {
  4     public static void main(String[] args) {
  5         // 多态的引入:
  6         // 变形金刚:变化为不同的形态:一会儿是机器人,一会儿变成汽车
  7         // 水:三种不同的形态:气态、液态、固态
  8
  9         // 多态:同一个对象,在不同的时间、场合表现出不同的形态或状态
 10
 11         // 比如:狗这个动物就是可爱啊!
 12         // 这句话其实有几层意思:
 13         // 1、狗是一种动物,也就是说狗从动物继承而来的,dog is an animal
 14         // 2、描述的重点在动物上,这个动物在我们描述的时候以狗这种形态出现的
 15         // 类似:猫这个动物就是要人哄啊!
 16
 17         // 多态的前提:
 18         // 1、继承是多态的基础,必须有继承的关系,才可以探讨多态
 19         // 2、要有override重写
 20         // 3、要有父类的引用(声明)指向子类的对象:父类    对象名   =  new  子类();    父类在前,子类在后
 21         //        对比:之前写法       子类    对象名   =  new  子类();
 22
 23         // 理解:
 24         // 狗        对象名   = new  狗();            狗  是 狗      √
 25         // 动物    对象名   = new  狗();            狗  是 动物  √
 26         // 狗    对象名   = new  动物();            动物  是 狗  ×
 27
 28 //        Son son = new Son();
 29 //        System.out.println(son);
 30
 31 //        Father obj = new Son();
 32 //        System.out.println(obj);
 33
 34         // 语法错误:Type mismatch: cannot convert from Father to Son
 35 //        Son obj = new Father();
 36 //        System.out.println(obj);
 37
 38         // 多态中成员的关系:
 39         // 1、成员变量
 40         //        编译时去赋值号左侧的类型里找,执行时去赋值号左侧的类型里找
 41         // 2、构造函数
 42         //        是否是多态的写法不影响,都是通过继承关系先找到父类的构造函数,执行后再走入子类的构造函数
 43         // 3、成员方法
 44         //        编译时去赋值号左侧的类型里找,执行时去赋值号右侧的类型里找
 45         // 4、静态成员变量
 46         //        编译时去赋值号左侧的类型里找,执行时去赋值号左侧的类型里找
 47         // 5、静态成员方法
 48         //        编译时去赋值号左侧的类型里找,执行时去赋值号左侧的类型里找
 49
 50         // 非多态写法
 51 //        Son son = new Son();
 52 //        System.out.println(son);        // cn.temptation.Son@15db9742
 53 //        System.out.println(son.i);        // 3
 54 //        son.show();                        // 子类的show方法
 55 //        System.out.println(son.m);        // 5
 56 //        System.out.println(Son.m);        // 5
 57 //        son.use();                        // 子类的静态use方法
 58 //        Son.use();                        // 子类的静态use方法
 59
 60         // 多态写法
 61         Father obj = new Son();
 62         System.out.println(obj);        // cn.temptation.Son@15db9742
 63         System.out.println(obj.i);        // 2
 64         obj.show();                        // 子类的show方法
 65         System.out.println(obj.m);        // 4
 66         System.out.println(Father.m);    // 4
 67         System.out.println(Son.m);        // 5
 68         obj.use();                        // 父类的静态use方法
 69         Father.use();                    // 父类的静态use方法
 70         Son.use();                        // 子类的静态use方法
 71
 72         // 注意:
 73         // 多态时,需要从  编译时  和  执行时  两个方面去观察
 74         // 多态中,非静态的成员方法在执行时去赋值号右侧的类型中找相应的方法进行调用,这种调用也称为   后期调用
 75     }
 76 }
 77
 78 // 父类
 79 class Father {
 80     // 成员变量
 81     public int i = 2;
 82     public static int m = 4;
 83
 84     // 构造函数
 85     public Father() {
 86         System.out.println("父类的构造函数");
 87     }
 88
 89     // 成员方法
 90     public void show() {
 91         System.out.println("父类的show方法");
 92     }
 93
 94     public static void use() {
 95         System.out.println("父类的静态use方法");
 96     }
 97 }
 98
 99 // 子类
100 class Son extends Father {
101     // 成员变量
102     public int i = 3;
103     public static int m = 5;
104
105     // 构造函数
106     public Son() {
107         System.out.println("子类的构造函数");
108     }
109
110     // 成员方法
111     public void show() {
112         System.out.println("子类的show方法");
113     }
114
115     public static void use() {
116         System.out.println("子类的静态use方法");
117     }
118 }

 1 package cn.temptation;
 2
 3 public class Sample07 {
 4     public static void main(String[] args) {
 5         // 不用装刘备的时候,可以做自己,就可以用自己特有的play方法
 6 //        LiuShan personEx = new LiuShan();
 7 //        personEx.work();
 8 //        personEx.play();
 9
10         // 让刘禅接替刘备的位置(多态的使用)
11         LiuBei person = new LiuShan();
12         System.out.println(person);                // cn.temptation.LiuShan@15db9742
13         person.work();
14         // 让刘禅装刘备时,不能做自己,不能使用自己特有的play方法
15         // 语法错误:The method play() is undefined for the type LiuBei
16 //        person.play();
17         // 问:非要使用子类中特有的成员方法,怎么办?     答:因为我们知道其对象其实是子类类型的对象,所以可以考虑使用一下强制类型装换
18         ((LiuShan)person).play();
19     }
20 }
21
22 // 父类:刘备
23 class LiuBei {
24     public void work() {
25         System.out.println("千辛万苦打江山!");
26     }
27 }
28
29 // 子类:刘禅
30 class LiuShan extends LiuBei {
31     // 成员方法
32     // 重写父类的成员方法work
33     public void work() {
34         System.out.println("被逼着做主公,也不知道有多难受!");
35     }
36
37     // 子类特有的成员方法play
38     public void play() {
39         System.out.println("玩的都乐不思蜀了!");
40     }
41 }

 1 package cn.temptation;
 2
 3 public class Sample08 {
 4     public static void main(String[] args) {
 5         // 多态的优点:
 6         // 1、使用多态,让程序有较好的扩展性
 7         // 2、使用多态,让程序由较好的健壮性(没有继承关系的两个类不能玩多态)
 8
 9         // 不使用多态的写法
10 //        BasketBall basketBall = new BasketBall();
11 //        basketBall.play();
12 //
13 //        FootBall footBall = new FootBall();
14 //        footBall.play();
15 //
16 //        VolleyBall volleyBall = new VolleyBall();
17 //        volleyBall.play();
18
19         // 使用多态的写法
20         // 写法1
21 //        Sport basketBall = new BasketBall();
22 //        basketBall.play();
23 //
24 //        Sport footBall = new FootBall();
25 //        footBall.play();
26 //
27 //        Sport volleyBall = new VolleyBall();
28 //        volleyBall.play();
29
30         // 写法2
31 //        Sport sport1 = new BasketBall();
32 //        sport1.play();
33 //
34 //        Sport sport2 = new FootBall();
35 //        sport2.play();
36 //
37 //        Sport sport3 = new VolleyBall();
38 //        sport3.play();
39
40         // 写法3(数组的动态初始化)
41         // 因为上面三个变量的类型都是一致的,所以考虑使用数组来存放一下,声明一个Sport类型的数组
42 //        Sport[] sports = new Sport[3];
43 //        sports[0] = new BasketBall();
44 //        sports[1] = new FootBall();
45 //        sports[2] = new VolleyBall();
46
47         // 写法4(数组的静态初始化)
48         Sport[] sports = {
49                 new BasketBall(),            // 匿名对象
50                 new FootBall(),
51                 new VolleyBall(),
52                 new Swim()
53         };
54
55         for (Sport item : sports) {
56             item.play();
57         }
58     }
59 }
60
61 // 父类:运动类
62 class Sport {
63     public void play() {
64         System.out.println("做运动");
65     }
66 }
67
68 // 子类:篮球类
69 class BasketBall extends Sport {
70     @Override
71     public void play() {
72         System.out.println("篮球的玩法");
73     }
74 }
75
76 class FootBall extends Sport {
77     @Override
78     public void play() {
79         System.out.println("足球的玩法");
80     }
81 }
82
83 class VolleyBall extends Sport {
84     public void play() {
85         System.out.println("排球的玩法");
86     }
87 }
88
89 class Swim extends Sport {
90     @Override
91     public void play() {
92         System.out.println("游泳的玩法");
93     }
94 }

 1 package cn.temptation;
 2
 3 public class Sample09 {
 4     public static void main(String[] args) {
 5         // 多态的缺点:
 6         // 使用多态,对于子类有但是父类没有的成员方法(子类特有的成员方法),无法使用
 7 //        Parent obj = new Child();
 8 //        obj.show();
 9
10         // 语法错误:The method use() is undefined for the type Parent
11 //        obj.use();
12
13         // 要想使用子类特有的成员方法,只有在明确其实该对象是子类类型的对象时,进行强制类型转换
14 //        ((Child)obj).use();
15     }
16 }
17
18 //class Parent {
19 //    public void show() {
20 //        System.out.println("父类的成员方法");
21 //    }
22 //}
23 //
24 //class Child extends Parent {
25 //    @Override
26 //    public void show() {
27 //        System.out.println("子类的成员方法");
28 //    }
29 //
30 //    public void use() {
31 //        System.out.println("子类特有的成员方法");
32 //    }
33 //}

 1 package cn.temptation;
 2
 3 public class Sample10 {
 4     public static void main(String[] args) {
 5         // 对于多态的缺点:使用多态,对于子类有但是父类没有的成员方法(子类特有的成员方法),无法使用,非要使用,怎么办?
 6         // 方法1、在父类中加上子类特有的成员方法,语法OK,但是不能这样写,因为这样就违背了父类设计的初衷
 7         // 方法2、因为子类实际在替代父类的事情,所以在编译阶段只能用父类中的成员方法,
 8         //            如果明确实际使用的是子类对象,使用时让其改为子类的类型,就可以使用其自己的成员方法了
 9         //            把父类类型的变量名(引用)强制类型转换为子类类型的引用,称为多态的向下转型
10
11 //        Parent obj = new Child();
12 //        obj.show();
13         // 语法错误:The method use() is undefined for the type Parent
14 //        obj.use();
15
16 //        Parent obj = new Child();
17 //        // 写法1
18         ((Child)obj).show();
19         ((Child)obj).use();
20 //        // 写法2
21 //        Child child = (Child) obj;
22 //        child.show();
23 //        child.use();
24 //
25 //        // 不转型
26 //        Child childEx = new Child();
27
28         // 所谓的转型:就是拿着赋值号右边的类型    和    赋值号左边的类型进行比较
29         //         右边的类型是左边类型的下级(子),向上转型
30         //         右边的类型是左边类型的上级(父),向下转型
31         Parent obj = new Child();            // 向上转型
32         Child child = (Child)obj;            // 向下转型
33
34         // 没有关系的两个类,是无法进行强制类型转换的
35         // 语法错误:Cannot cast from Parent to Other
36 //        Other other = (Other)obj;
37     }
38 }
39
40 class Parent {
41     public void show() {
42         System.out.println("父类的成员方法");
43     }
44 }
45
46 class Child extends Parent {
47     @Override
48     public void show() {
49         System.out.println("子类的成员方法");
50     }
51
52     public void use() {
53         System.out.println("子类特有的成员方法");
54     }
55 }
56
57 class Other {
58     public void show() {
59         System.out.println("其他类的成员方法");
60     }
61 }

 1 package cn.temptation;
 2
 3 public class Sample11 {
 4     public static void main(String[] args) {
 5         // 多态的一些问题:
 6         // 1、父类、子类都有的同名同参数列表成员方法,编译时找父类的成员方法,执行时找子类的成员方法
 7         // 2、父类有、子类没有的成员方法,编译时找父类的成员方法,执行时找父类的成员方法(因为子类中没有重写该成员方法,所以使用父类中的成员方法)
 8         ParentTest obj = new ChildTest();
 9         obj.show();
10     }
11 }
12
13 class ParentTest {
14     public void show() {
15         System.out.println("父类有、子类没写的成员方法");
16     }
17 }
18
19 class ChildTest extends ParentTest {
20
21 }

 1 package cn.temptation;
 2
 3 public class Sample12 {
 4     public static void main(String[] args) {
 5         Animal animal = new Dog();
 6         animal.eat();
 7 //        animal.guard();            // 语法错误
 8
 9         Dog dog = (Dog) animal;
10         dog.guard();
11
12         // 执行出错,产生异常:java.lang.ClassCastException: cn.temptation.Dog cannot be cast to cn.temptation.Cat
13         // 原因:
14         // 第5行的animal变量是一个引用,animal变量的类型是Animal类类型,它指向堆内存中创建出的Dog类型的空间
15         // 下句的强制类型转换,是要把animal这个引用转换为Cat类型,如果正常的使用,那么这个cat变量的引用,应该指向堆内存中创建的Cat类型的空间
16         Cat cat = (Cat) animal;        // 这句语法上没有错误,编译可以通过,是因为有继承关系的子类和父类可以进行向上转型 和 向下转型
17         cat.eat();
18         cat.bask();
19         // 本质上这样的写法就是"指鹿为马"
20
21         // 平行的两个子类,是无法进行强制类型转换的
22         Dog dogEx = new Dog();
23         Cat catEx = new Cat();
24         // 语法错误:Cannot cast from Dog to Cat
25 //        catEx = (Cat)dogEx;
26     }
27 }
28
29 class Animal {
30     public void eat() {
31         System.out.println("动物都会吃");
32     }
33 }
34
35 class Dog extends Animal {
36     @Override
37     public void eat() {
38         System.out.println("狗吃肉");
39     }
40
41     public void guard() {
42         System.out.println("看门");
43     }
44 }
45
46 class Cat extends Animal {
47     @Override
48     public void eat() {
49         System.out.println("猫吃鱼");
50     }
51
52     public void bask() {
53         System.out.println("晒太阳");
54     }
55 }

转载于:https://www.cnblogs.com/iflytek/p/6539415.html

【原】Java学习笔记018 - 面向对象相关推荐

  1. JAVA学习笔记之面向对象(一)

    作为初入开发的萌新,我根据黑马程序员的教学视频和课件整理总结,记录下自己的JAVA学习,方便巩固和交流.每篇笔记首先回顾知识点,然后贴上代码和执行结果,最后进行小结.若有不正之处或者有疑问,欢迎指出, ...

  2. 【原】Java学习笔记020 - 面向对象

    1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 // ...

  3. Java学习笔记:04面向对象-内部类_访问修饰符_final

    04面向对象-内部类/访问修饰符/final 1.static的介绍 static:关键字,静态的 static的作用是用来修饰类中的成员 2.访问一个类中的某一个成员变量 方法一: _1.创建对象 ...

  4. 疯狂java学习笔记之面向对象(二) - 成员变量与局部变量

    Java变量按其作用域可分为:成员变量和局部变量.注意:在Java中是没有全局变量这个概念的 一.成员变量: 成员变量是在类中定义的变量,具体可分为类变量与实例变量--有无static修饰 实例变量的 ...

  5. 疯狂java学习笔记之面向对象(三) - 方法所属性和值传递

    方法的所属性: 从语法的角度来看:方法必须定义在类中 方法要么属于类本身(static修饰),要么属于实例 -- 到底是属于类还是属于对象? 有无static修饰 调用方法时:必须有主调对象(主语,调 ...

  6. 【Java】Java学习笔记(2)——Java面向对象基础作业函数题

    本人私人博客:Megalomania,大部分文章会现在博客上传,有不足之处欢迎指正. 学校小学期Java课程的练习题,留个档便于以后需要时候有例子可以回忆,写的烂的地方请多多包含 1.求两个数值之和 ...

  7. Java学习笔记 六、面向对象编程中级部分

    Java学习笔记 六.面向对象编程中级部分 包 包的注意事项和使用细节 访问修饰符 访问修饰符的注意事项和使用细节 面向对象编程三大特征 封装 封装的实现步骤(三步) 继承 继承的细节问题 继承的本质 ...

  8. java学习笔记13--反射机制与动态代理

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...

  9. Java学习笔记Day02

    Java学习笔记Day02 一.细化Hello程序 1.详解代码 //公有的类,叫做Hello public class Hello{//主方法public static void main(Stri ...

最新文章

  1. fetch git pull 切换_每天提交 Git 太烦?直接用 Python 就好了!
  2. python趣味编程10例-Python趣味编程100题
  3. java iterator map_Java循环遍历输出map方法
  4. 有限元ansys/lsdyna学习笔记-组件component与组元part_02
  5. c语言源程序结构是怎样的?
  6. 常见的数据增强项目和论文介绍
  7. logistic回归列线图(nomogram)的多种绘制方法
  8. Visual Studio2019配置备忘
  9. spark处理大数据实例
  10. 移动硬盘计算机无法打开硬盘,移动硬盘打不开怎么办 硬盘打不开解决方法【详解】...
  11. VMware通过vmdk安装Kali linux
  12. 多线程编程实例(使用CompletableFuture)
  13. 使用屏幕录制专家--录制视频技巧
  14. 用贾樟柯访谈评《疯狂的程序员》
  15. Matlab数值分析编程:牛顿下山法解方程
  16. Prometheus原理详解
  17. 【解决方案】国标GB28181协议摄像头直播EasyGBS视频平台联合城管执法局搭建4G移动视频监控系统方案
  18. Vanilla JavaScript 哈希 URL 路由器
  19. 移动端点击input不触发光标(原生js)
  20. 中软国际的违法罪行,我们用行动来制裁

热门文章

  1. JAVA-生成Cron表达式生成工具类
  2. CUDA如何选取Blocks和Threads
  3. 达到 50 事件的 crypt32 阈值,将挂起记录 60 秒
  4. win10 任务管理器没了
  5. c++实现argmax
  6. 微信小程序 API 简介
  7. Bugku S3 AWD排位赛-5 pwn
  8. Python海象运算符的使用
  9. D.Teacher_Cadre
  10. 电脑减少为硬件保留2.1G、4G的解决方法