1.总体来说java像一个不开窍的规则制定者。
包名,类型,太实在了。
文件名和类名必须对应,一个文件只能有一个 PUBLIC的类。
定义了包名,必须按这个路径去放置 目标文件。
相比 c#的 虚拟命名空间。
可能java最初就是设计出来让人用记事本来写代码的?而且还怕人找不到类放在哪个目录,哪个文件下。
一个文件只能一个public类,简直无语,所以才会产生静态内部类,这种怪胎的概念。
有非静态类还好解释,让非静态类实现顶级类应该实现的接口,让顶级类看起来更简洁。但是静态内部类 真的是java的特色奇葩。****
2.默认的访问是private+ packet. .奇怪的设定。
突然想到了这个设定的用意。还一直在回想vs中,有解决方案,项目这样的设定,并可以独立开发。非常简单的引用。
突然就想到。默认的访问权限就是 非常适合解决分层的问题。一个包内,全部都是包内访问权限。之后再来一个public 的类。这不就是妥妥的分层设计不。不过加大了工作。要新一个pulick类。还是。。。
3.不可以初始化泛型数组 T[] a=new T[3]; 错误的。
4.java 的异常处理。和c#一样,可以在catch中自己处理,也可以只做抛出动作,让使用者自己处理的机制。
而且java 更明确了。在方法后面跟了一个throws 关键字,明确的告诉使用者,我不会处理,你自行处理某些异常。
这样让每个异常从最底层到最上层,确保一定会有一个处理 者。
5.匿名类所使用外部变量必须final
我自己的感觉是因为有匿名,所以无法控制语句的执行顺序,因为匿名函数可能随时被一个新线程处理。把变量设置为null或其他对象。
所以非常影响主函数的执行,主函数的逻辑可能被完全打乱。出现问题。都无法排错。因为非线性执行。
所以到匿名内部不能使用变量的正常引用,所以给一个不正常的引用。就是不让你指向其他对象,无法修改指针本身。
这里有比较正确的解释:https://zhuanlan.zhihu.com/p/29245059
基本原因就是,当匿名类使用栈上的数据(方法内部的数据)时候,如果方法内部或匿名内部修改了指针,由于编译的问题,无法让2者保持一致。所以干脆2个地方都不让修改指针。恩,解释目前是完美自洽的。
如果需要改指针,那么用普通类代替匿名类,反正自己也不是很喜欢匿名类。不好看,而且减低了复用的意识。
6.为什么需要内部类
2种,非静态类和静态类,我觉得分别叫扩展类和帮助类,更容易让人知道这2中类的作用。
Compelling reasons for using nested classes include the following:
It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.
It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared
private
. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.
Static Nested Classes:除了命名空间需要使用顶级类 topclass.myclass xxx=new topclass.myclass() .其他和顶级类一样。虽然有static 也需要new.
一个很明显的时候场合就是建立一个只有外部类会用到的帮助类。
Non-Static Nested Classes(inner class) .就可以看成顶级类的一个 内部变量,如内部的一个string之类。
一个很明显的使用场合就是多接口的时候,用一个内部类实现接口,把接口实现从外部类放到内部类,这样可以让外部类代码看起来更整洁。如此,内部类其实就是外部类的一部分,就像一个成员变量。
7.如何选择,
就看是否需要顶级类的成员变量。需要那么非静态。 不需要那么静态。
static看成一个顶级类就可以了。只不过访问路径被外部类套住了。这个关键字又是一个误导关键字。static在这里和全局,不需要new没有关系。statci换成 Top, outer ,任何表示外部独立的单词都比static 好。****
而非静态类,他就看成一个类的成员变量就好了,只不过这个成员变量,可以有自己变量和方法而已。唯一注意的就是它本身不能有static变量,感觉真无聊。干脆让它有static变量不就好了。搞的要多记一个特殊点。而且这个特殊点和逻辑无关。因为就算他有static变量。感觉也不影响任何操作。没有反而让人更不适应。他有static会怎样。不就和外部类的static变量一样的使用?而且有的话。还可以限制static变量的使用范围。缩小到内部类。
很多可行可不行的东西。不需要解释那么多无聊的意义。
8 。值和引用。
不算java的特色了。大部分高级语言都有。这里小结下。
没有类之前,基本数据类型占用的内存是固定的并且是小的,如4字节,8字节等。所以基本类型一般是直接放入到栈中。如此,当作为参数传递时,也是可以直接把数据本身copy一份传递过去。导致函数内外是2份数据,互不影响。
而有了类,类占用的内存不可能是固定大小的(但是每个类占用的内存是确定的,不会变化,只是大小不同),有的会很大。所以最好放入到堆中,而用一个4字节(32位系统)的地址来指代它。所以作为参数,是把指针传递,所以函数内外是同一份数据,2个存放同一地址的4字节空间。
这里比较好理解。
但是有个类,string,却不符合典型类的特性。string作为参数,函数内外修改后,并不会是同一份数据。
个人的猜测还是和编译有关,因为string的特性已经不符合人的习惯而且还和其他类也不同,所以肯定是没有办法才这样设计。
猜测是:其他类,如果只包含基本类型。那么修改后,是不会改变内存大小的。
而string类,修改值是会改变内存大小的。这个就不好办了。不能在原来堆中直接修改数据,因为大小是不一样。直接扩大也不能保证后面有足够大的空间。只能让系统按算法给个适合大小的另外的堆空间。
所以string类,每次修改值,其实都是new了一次。既然new了一次。那么函数内外当然是2分数据了。别说函数内外。就是上下2行,修改数据也是不同堆地址,不同引用。 所以是因为现实的无奈导致语意的不统一。
总结
基本类型,固定大小,且小。所以可以到处copy本身。如 int 3. 到处传递和保存 00000011 ,互不干涉。
典型类:放入堆中,用指针代替,到处传递指针,修改原堆数据来进行修改数据。(如里面有个int32变量,4改为3000,在原来4字节的地方修改,可以原地改)
string:放入堆中,用指针代替,到处传递地址,但是无法在原堆数据进行修改(因为对于string修改基本会导致所占空间变化),每次修改必须换一个新的地址。
所以如果想函数外得到修改后的string或者基本数据,那么把string和基本类型放入到类就好了。所以如果函数内 abc=new xxx();也当然不会修改函数外了。因为没有修改指向堆的数据,而是换了一个地址。
本质清楚了,任何情况只要推一下就好。
所以理论上java缺少一个关键字,控制典型类被传递后,不会被修改数据本身。好像没有c++的const关键字。final 只能给基本类型控制数据不能修改