java学习心得与想法

1. 弄清楚继承与多态:

public class first_test {
private int a;
first_test(int aa){
    a = aa;
}

public int geta(){
    System.out.println("父类的a:"+a);
    return a;
}}

class sc extends first_test {
private int a;
sc(int aa,int bb){super(aa);a = bb;}
public int geta(){
     System.out.println("子类的a:"+a);
     System.out.println("父类的geta:"+super.geta());
     return a;
}
}

class test{
    public static void main(String[] args){
        System.out.println ("hello world!");
        sc sss = new sc(111,222);
        sss.geta();
    }
}
输出:
hello world!
子类的a:222
父类的a:111
父类的geta:111

可以发现多态不仅仅限于继承的方法,连私有变量也是“多态”的,虽然在父类中有private a,但是子类中也是可以定义a这个属性的,并且用起来也是独立的(父类中的a可以通过父类的public函数访问,子类的a本身也可以访问,两个是完全不同的东西)

所以说虽然子类把父类的什么东西都继承过来了,子类有了这些属性和方法可以用,但是真正能访问的是父类的public 属性和方法,观察下面代码的区别,也恰好验证了java所有的变量名都是“引用”的性质:

public class first_test {
public int a;/注意区别
first_test(int aa){
    a = aa;
}

public int geta(){
    System.out.println("父类的a:"+a);
    return a;
}}

class sc extends first_test {
public int a;///注意区别
sc(int aa,int bb){super(aa);a = bb;}
public int geta(){
     System.out.println("子类的a:"+a);
     System.out.println("父类的geta:"+super.geta());
     return a;
}
}

class test{
    public static void main(String[] args){
        System.out.println ("hello world!");
        sc sss = new sc(111,222);
        sss.geta();
    }
}
hello world!
子类的a:222
父类的a:111
父类的geta:111

(结果跟上面一样)

public class first_test {
public int a;/注意区别
first_test(int aa){
    a = aa;
}

public int geta(){
    System.out.println("父类的a:"+a);
    return a;
}}

class sc extends first_test {
//public int a;///注意区别
sc(int aa,int bb){super(aa);a = bb;}
public int geta(){
     System.out.println("子类的a:"+a);
     System.out.println("父类的geta:"+super.geta());
     return a;
}
}

class test{
    public static void main(String[] args){
        System.out.println ("hello world!");
        sc sss = new sc(111,222);
        sss.geta();
    }
}
hello world!
子类的a:222
父类的a:222
父类的geta:222

(子类父类公用同一个a)
证明a只是指向对象属性的一个“标签”而已,实际上的内存是一直存在的。

2. 一个java文件中可包含多个main方法

java中的main方法是java应用程序的入口,java程序在运行时,首先调用执行main方法。但并不是说java中只能有一个main方法,不同类中都可以包含main方法。当JVM进行编译时,会提示选择其中一个main方法作为编译的入口
在这里插入图片描述

3. 接口的形象理解,以及接口与抽象类

https://www.jb51.net/article/76738.htm
通过上文,我想大家对接口和接口的思想内涵有了一个了解,那么什么是面向接口编程呢?我个人的定义是:在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。

这样做的好处是显而易见的,首先对系统灵活性大有好处。当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。甚至可以在不改动上层代码时将下层整个替换掉,就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘,计算机其他地方不用做任何改动,而是把原硬盘拔下来、新硬盘插上就行了,因为计算机其他部分不依赖具体硬盘,而只依赖一个IDE接口,只要硬盘实现了这个接口,就可以替换上去。从这里看,程序中的接口和现实中的接口极为相似,所以我一直认为,接口(interface)这个词用的真是神似!

使用接口的另一个好处就是不同部件或层次的开发人员可以并行开工,就像造硬盘的不用等造CPU的,也不用等造显示器的,只要接口一致,设计合理,完全可以并行进行开发,从而提高效率。

2.关于抽象类与接口
(当一个全为抽象类与接口之间的选择,那要看是is a的关系还是需要提供统一的接口/协议has a 的关系(表达的语义会不一样))

看到回复中这是讨论的比较激烈的一个问题。很抱歉我考虑不周没有在文章中讨论这个问题。我个人对这个问题的理解如下:

如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。但是,难道接口的存在是为了实现多重继承?当然不是。我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。

看到有朋友对IPerson这个接口的质疑,我个人的理解是,IPerson这个接口该不该定义,关键看具体应用中是怎么个情况。如果我们的项目中有Women和Man,都继承Person,而且Women和Man绝大多数方法都相同,只有一个方法DoSomethingInWC()不同(例子比较粗俗,各位见谅),那么当然定义一个AbstractPerson抽象类比较合理,因为它可以把其他所有方法都包含进去,子类只定义DoSomethingInWC(),大大减少了重复代码量。

但是,如果我们程序中的Women和Man两个类基本没有共同代码,而且有一个PersonHandle类需要实例化他们,并且不希望知道他们是男是女,而只需把他们当作人看待,并实现多态,那么定义成接口就有必要了。

总而言之,接口与抽象类的区别主要在于使用的动机,而不在于其本身。而一个东西该定义成抽象类还是接口,要根据具体环境的上下文决定。

多态性
(1)什么是多态性(注意:多态与多态性是两种概念)
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。总而言之就是在不考虑对象的类型的情况下直接使用对象。

Animal[ ]   A = { new Catnew Dognew Fish};
for each animal in A
	animal.eat( );

这里的eat可以调用不同动物的具体实现方法,前提是Animal中已经有这个类或者抽象类,子类进行了重写。

(1)增加了程序的灵活性
  以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
(2)增加了程序额可扩展性
  通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
多态
多态指的是一类事物有多种形态

4. Java中各种修饰符与访问修饰符

https://www.cnblogs.com/Annoying/p/5403957.html
(注意文中所说的可以访问是指可以 在类中new一个实例,从而可以调用其变量或者方法,static 的不用实例化,可以直接使用,而且所有实例(对象)共享该变量/方法,先后访问会影响内部状态,所有新建的父类实例或者子类实例都会访问这同一个变量)

class father{
    public static int aaaa = 0;
    public static void adda(){
        aaaa++; }}

public class asdasda extends father{
    public static void main(String[] args) {
    aaaa++;
    father ff = new father();
    father ff1 = new father();
    ff1.adda();// aaaa = 2
    ff.adda();// aaaa = 3;
    asdasda ff2 = new asdasda();
    ff2.adda();//aaaa = 4;
    aaaa++; System.out.println(aaaa);}}//aaaa = 5;
class father{
    public static int aaaa = 0;
    public static void adda(){
        aaaa++; }}

public class asdasda extends father{
    public static int aaaa;//注意这里的改动
    public static void main(String[] args) {
    aaaa++;
    father ff = new father();
    father ff1 = new father();
    ff1.adda();// aaaa = 2
    ff.adda();// aaaa = 3;
    asdasda ff2 = new asdasda();
    ff2.adda();//aaaa = 4;
    aaaa++; System.out.println(aaaa);}}//aaaa = 5;
   ***在子类中重新定义 public static int aaaa 之后,发现子类一直操作的子类的aaaa了,而父类的aaaa++和adda()都是操作父类继承过来的aaaa

(这就是继承与隐藏)

静态方法是用操作这个类型的,方法被该类的所有实例共享。
而实例方法用操作单个实例,不被该类所有实例共享。
静态方法中不能调用实例方法,也不能访问实例变量。
(只能通过在其中new实例对象之后访问)
实例方法可以调用静态方法,也能访问静态变量。
总之静态方法对应的是类型,即Class,类。但是实例方法对应的是实例,即object,对象。

Java抽象类中不能有静态的抽象方法。
  原因:抽象类是不能实例化的,即不能被分配内存;而static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了:抽象类不能被分配内存,而static方法必须被分配内存。所以抽象类中不能有静态的抽象方法。
  另外,定义抽象方法的目的是重写此方法,但如果定义成静态方法就不能被重写。

**5. 关于A a,A a = null, A a = new A( )

值为null的对象为什么可以调用静态方法而不报错(空指针)呢?**
A a 申明一个A 类的对象,但是没有实例化,去用a的成员变量或者函数都会报错;
A a = null同上,按理说应该去用也会报错,但是java有优化,可以调用静态成员。
在这里插入图片描述

从class文件可以看出,在编译的时候JVM发现调用静态方法的对象为null值后,自动将null值的对象替换为了类名调用。
A a = new A( )正确利用构造函数初始化(实例化)并将引用传递给对象a。

类的静态属性生存于静态内存区,类的实例生存于堆内存区,也就是一旦类被加载后,实例存在不存在,并不影响静态变量,而静态变量支持类直接访问和实例直接访问,只要静态变量依然存在,任何类实例都能访问

6. 关于java的参数传递方式(形参,实参。值传递,引用传递)

就 Java 语言本身来说,只有值传递,没有引用传递。
根据 值传递,引用传递的定义来说:
Java 中的基本类型,属于值传递。
Java 中的引用类型,属于引用传递。
Java 中的 String 及包装类,属于特殊群体(因为其中都有final修饰,赋值的时候都是相当于new了一个新的对象),作为形参时,由于每次赋值都相当于重新创建了对象,因此看起来像值传递,但是其特性已经破坏了,值传递、引用传递的定义。因此他们属于引用传递的定义,却表现为值传递。

基本类型直接保存值在栈中,引用类型(包括String和包装类)保存值在堆中,栈中有其引用(指针)指向该值
函数传参时,不管是基本类型还是引用类型,都要 拷贝一份 栈中的内容作为形参,对形参进行操作。所有基本类型实参交换值不会发生,包装类型因为有final,相当于形参指向了新new的对象,也不会发生交换,而引用类型虽然也拷贝了,但是拷贝的指针(引用),仍然是指向堆中那一块数据的,所以可以对原来的实参进行操作

所以说,不管栈中的数据怎么变,都不会影响实参的值(改变的都是栈中的拷贝形参),只有通过调用改变堆中的值的方法才能改变实参。

      public class leecodetest {
public static void swap (Integer a, Integer b)
{
    Integer temp = a ;
    a = b;
    b = temp;
}
    public static void main(String[] args) {
        Integer i1 = new Integer(1);
        Integer i2 = new Integer(2);
        swap(i1,i2);
        System.out.println(i1);
        System.out.println(i2);
//输出:1  2
}}

在这里插入图片描述
(String和各包装类都类似于上图这种)

public class leecodetest {
public static void swap (leee a, leee b)
{
    leee temp = a ;
    a = b;
    b = temp;
}//这里也只是交换了形参的地址,对实参没一点影响
    public static void main(String[] args) {
        leee i1 = new leee();
        leee i2 = new leee();
        i1.a = 1;
        i2.a = 2;
        swap(i1,i2);
        System.out.println(i1.a);
        System.out.println(i2.a);
//输出:1  2
}}
public class leecodetest {
public static void swap (leee a, leee b)
{
    int temp = a.a ;
    a.a = b.a;
    b.a = temp;
}//这才是真正通过地址操作了实参中的数据
    public static void main(String[] args) {
        leee i1 = new leee();
        leee i2 = new leee();
        i1.a = 1;
        i2.a = 2;
        swap(i1,i2);
        System.out.println(i1.a);
        System.out.println(i2.a);
//输出:2  1
}}

上图这才是真正通过地址操作了实参中的数据

7. 接口和抽象类或者父类都可以作为方法返回值,只要返回的对象是他们的实现类对象或者子类对象就行

8. tm的单元测试的前提是该类也是public的,我干

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值