在Java中常用的是包(Package),较少提到NameSpace的概念。Java官方文档中这样说:
为了使类型更易于查找和使用,避免命名冲突并控制访问,程序员将相关类型的组捆绑到包中。 定义:包是一组提供访问保护和名称空间管理的相关类型。 请注意,类型是指类、接口、枚举和注释类型。 枚举和注解类型分别是特殊类型的类和接口,因此在本课中通常将类型简称为类和接口。
根据这里的概念,Package基本上是对应C#的NameSpace的。
无论是Java还是C#,每个类都有属于一个包/命名空间:
package cn.flylolo.entity;
public class Pig extends Animal{
}
namespace cn.flylolo.entity;
public class Pig : Animal{
}
import cn.flylolo.entity.Pig;
using cn.flylolo.entity.Pig;
C#的命名空间别名:若要引用同名的不同类,处理方式都是写全包/命名空间的名称。C#中觉得较长不美观可以在using的时候设置别名:
using entityPig = cn.flylolo.entity.Pig;
在代码中可以直接使用别名引用。
上一节,Java的包与C#的命名空间类似,但针对访问修饰符,包又与C#的程序集类似。
C# | Java | 含义 |
---|---|---|
public | public | 相同,访问不受限制。 |
protected | C#,访问限于包含类或派生自包含类的类型。 | |
private | private | 访问限于包含类。 |
internal或不添加修饰符 | 不添加修饰符 | 同一(包/程序集)可访问。 |
protected internal | protected | 相同,访问限于当前(包/程序集)或派生自包含类的类型。 |
private protected | 访问限于包含类或当前程序集中派生自包含类的类型。 自 C# 7.2 之后可用。 |
Java中,一个.java文件中,只允许有一个Public的类,并且文件名与此类名一般相同。
C#中则无上述限制。
public final class Shape
public sealed class Shape
注意: JDK15的时候,Java也提供了sealed关键字,用于限制继承,例如下列代码
public sealed class Shape permits Circle, Square, Rectangle {
}
通过sealed+permits两个关键字,限制了子类只能是Circle, Square, Rectangle这三个。
C#的内部类比较简单,类似如下代码:
namespace cn.flylolo.nestedclass;
/**
* @author luozhichao
* @date 2021/10/15 17:50
*/
public class OuterClass
{
public String outerClassName = "outerClass's name";
public void printNestedClassName()
{
//无法直接调用内部类的变量
//Console.WriteLine(NestedClass.nestedClassName);
Console.WriteLine(NestedStaticClass.nestedClassName);
}
public class NestedClass
{
public String nestedClassName = "nestedClass's name";
public void printOuterClassName()
{
//error 不可以直接调用外部类的对象
//Console.WriteLine(outerClassName);
}
}
public static class NestedStaticClass
{
public static String nestedClassName = "NestedStaticClass's name";
public static void printOuterClassName()
{
//error 不可以直接调用外部类的对象
//Console.WriteLine(outerClassName);
}
}
}
class Test
{
public static void main(String[] args)
{
OuterClass.NestedClass nestedClass = new OuterClass.NestedClass();
//可以直接调用静态内部类的方法。
string str = OuterClass.NestedStaticClass.nestedClassName;
}
}
代码中做了一些注释,可以看到,对于非静态的内部类,外部类就像给其加了一层“命名空间”,可以通过new OuterClass.NestedClass()
的方式进行创建。
对应静态内部类,可以通过OuterClass.NestedStaticClass
的方式直接调用其方法和属性,当然这也由对应的访问修饰符决定,例如将NestedStaticClass
设置为private
,则OuterClass
可以直接调用NestedStaticClass
,而上例中的Main方法则无法调用NestedStaticClass
了。
再看一下Java的内部类:
public class OuterClass {
public String outerClassName = "outerClass's name";
public void getNestedClassName() {
String staticString = NestedStaticClass.staticString;
//无法直接调用非静态内部类的变量
//String str = NestedClass.nestedClassName;
}
public NestedClass getNestedClass() {
//可以直接new
return new NestedClass();
}
class NestedClass {
public String nestedClassName = "nestedClass's name";
public void printOuterClassName() {
//可以直接调用外部类的对象
System.out.println(outerClassName);
}
public OuterClass getOuter() {
//返回外部类实例
return OuterClass.this;
}
}
static class NestedStaticClass {
public String nestedClassName = "NestedStaticClass's name";
public static String staticString = "staticString";
public void printOuterClassName() {
//error 不可以直接调用外部类的对象
//System.out.println(outerClassName);
}
//error 无法返回外部类实例
// public OuterClass getOuter(){
// return OuterClass.this;
// }
}
}
class Test{
public static void main(String[] args) {
//不允许直接通过new的方式创建OuterClass.NestedClass
//OuterClass.NestedClass nestedClass1 = new OuterClass.NestedClass();
//只能通过外部类的实例创建内部类
OuterClass outerClass = new OuterClass();
//通过方法返回内部类实例
OuterClass.NestedClass nestedClass = outerClass.getNestedClass();
//通过.new关键字
OuterClass.NestedClass nestedClass1 = outerClass.new NestedClass();
//通过内部类实例获取外部类实例
System.out.println(nestedClass1.getOuter().outerClassName);
nestedClass.printOuterClassName();
String staticString = OuterClass.NestedStaticClass.staticString;
OuterClass.NestedStaticClass nestedStaticClass = new OuterClass.NestedStaticClass();
System.out.println(nestedStaticClass.nestedClassName);
}
}
可见,Java的内部类“玩法比较多,完全写来下可以说是一个比较大的专题了,简要列举一下与C#的内部类的不同之处。