站内搜索: 请输入搜索关键词
当前页面: 图书首页 > NET For Java Developers Migrating To C#

NET For Java Developers Migrating To C#

[ directory ] Previous Section Next Section

4.2 Classes

Although classes constitute the fundamental concept in Java, in C# they are one of the various types supported by the runtime. An instance of the System.Type class can be a class, an interface, a value type, an array, a pointer, or an enumeration. Chapter 7 discusses System.Type.

A class can be thought of as the metadata, or the definition, of an object. A class has members, and these can be its constructors, methods, fields, properties, and operators. Members help maintain and query the state of the objects created by a class. Members that maintain the state of any one object are called instance members, and members that maintain the state of all objects created on that class are called static members. Before we explore the instance and static members of a class, we will quickly describe some class access modifiers.

Because this chapter is about objects, inheritance automatically comes into play. Later sections mention the significance of access modifiers in the context of inheritance. However, Chapter 5 gives a more comprehensive treatment of inheritance.

4.2.1 Class Modifiers

Class modifiers are keywords that can go in front of the class definition. Modifiers can denote access or behavior. Class access modifiers are internal, public, private, and protected. Non-access-based modifiers are sealed, abstract, and new. We will first explore class access modifiers.

internal

When a class has no access modifier specified, the default access level is internal. An internal class is accessible only within files in the same assembly.

public

A public class has no restrictions on its accessibility.

Top-level types, which are not nested into other types, can have only internal or public accessibility. The default accessibility for these types is internal.

Nested types, which are members of other types, can have declared accessibilities as indicated in Table 4.2.

Table 4.2. Nested Types

Members of

Default Member Accessibility

Allowed Declared Accessibility of the Member

enum

public

None

class

private

public protected internal

  

private protected internal

interface

public

None

struct

private

public internal private

Listings 4.3 and 4.4 illustrate the access modifier keywords. Listing 4.3 defines three classes in a People namespace. The three classes (Developer, Actress, and Scientist) have default access, public access, and internal access, respectively. A Test class in Listing 4.4 is used to access these classes.

Listing 4.3 Sample Classes with Different Access Modifiers (C#)
using System;
namespace People {
  public class Developer {
    public void Fears (Object o) {
      Console.WriteLine("A developer fears "+o);
    }
  }
  class Actress {
    public void Fears (Object o) {
      Console.WriteLine("An actress fears "+o);
    }
  }
  internal class Scientist {
    public void Fears (Object o) {
      Console.WriteLine("A scientist fears "+o);
    }
  }
}
Listing 4.4 A Driver Class That Accesses the Classes Defined in Listing 4.3 (C#)
using People;
public class Test {
  public static void Main(string[] args) {
    Developer d = new Developer();
    d.Fears(new Actress());
    Actress a = new Actress();
    a.Fears(new Scientist());
  }
}

When you compile Listings 4.3 and 4.4 and run them in a single assembly, it is clear that classes with the public, internal, and default access modifiers can be accessed by any class in that assembly (a unit of deployment in C#). Note that even if the class access modifiers are restrictive, the methods of a class can have more liberal access modifiers. Hence, the classes Scientist and Actress can have public methods.

To quickly prove that classes Actress and Scientist in Listing 4.3 are inaccessible to the Test class in Listing 4.4 if it is in a different assembly, let's compile Listing 4.3 using csc /t:library Listing 4.3.cs. This creates a Listing 4.3.dll file. Now try compiling Listing 4.4 using the /r:Listing 4.3.dll option. The compiler gives the following output:


Listing4.4.cs(4,21): error CS0122: 'People.Actress' is inaccessible due to its protection 
graphics/ccc.giflevel
Listing4.4.cs(5,9): error CS0122: 'People.Actress' is inaccessible due to its protection 
graphics/ccc.giflevel
Listing4.4.cs(6,21): error CS0122: 'People.Scientist' is inaccessible due to its 
graphics/ccc.gifprotection level

Access modifiers in Java follow somewhat similar rules.

  • In Java, a public class can be accessed from any package by any class. A class without access modifiers can be accessed only by classes in the same package. The access modifiers private and protected are allowed only on inner classes. Multiple packages and classes can be deployed in a single .jar file. A Java class with package-level access cannot be accessed by classes outside the .jar, nor by classes in the same .jar that are not in the same package.

  • In C#, the default and internal access levels disallow classes outside the assembly to access a class. However, classes inside the assembly can access these classes.

private and protected

The access modifiers private and protected can be put on classes that are part of an outer enveloping class. Such a nested class behaves like any other member (field, method, property) of a class. Nested classes can therefore be private or protected and are accessible only to objects of that class and not to objects of other classes or subclasses. Listing 4.5 shows a nested class with private and protected access. Only the Developer class can access the ApplicationDeveloper and WebDeveloper classes.

Listing 4.5 Access to Private and Protected Inner Classes (C#)
using System;
namespace People {
  public class Developer {
    public void Fears (Object o) {
      Console.WriteLine("A developer fears "+o);
      ApplicationDeveloper ad = new ApplicationDeveloper();
      ad.Fears(o);
      WebDeveloper wd = new WebDeveloper();
      wd.Fears(o);
    }
    private class ApplicationDeveloper {
      public void Fears (Object o) {
        Console.WriteLine("An application developer fears"
                                     +o+" and software bugs ");
      }
    }
    protected class WebDeveloper {
      public void Fears (Object o) {
        Console.WriteLine("A web developer fears "
                                       +o+" and slow modems ");
      }
    }
  }
  class Actress {
    public void Fears (Object o) {
      Console.WriteLine("An actress fears "
                                        +o+" a makeup famine");
    }
  }
  internal class Scientist {
    public void Fears (Object o) {
      Console.WriteLine("A scientist fears "
                                   +o+" and loss of gravity ");
    }
  }
}

Non-access-based modifiers of a C# class can be abstract, sealed, or new.

abstract

Abstract classes have the following features:

  • An abstract class cannot be instantiated.

  • An abstract class can contain abstract methods and accessors.

  • You cannot modify an abstract class using the sealed modifier, and this means that the class cannot be inherited.

  • A nonabstract class derived from an abstract class must include actual implementations of all inherited abstract methods and accessors.

  • An abstract C# class is equivalent to an abstract Java class.

Abstract classes are ideal when you want to put most of the functionality in a base class, leaving a few methods for subclasses to implement so that they can plug in their specific behavior. For example, a class that models persisting an object's state to the database can be declared as abstract. The general logic of saving can be captured in the base class, and the subclasses supply the names of the database tables where the data is to be stored. This practice helps to keep all the complex code in one base class, and subclasses end up being fairly simple.

abstract class PersistentObject {
  public void Save() {
    string tableName = GetTableName();

    //Do your saving here..
  }
  abstract public string GetTableName();
}

class Person : PersistentObject {
  public string GetTableName() { return "PERSONS_TABLE"; }
}
sealed

A sealed class cannot be inherited. It is an error to use a sealed class as a base class. Use the sealed modifier in a class declaration to prevent accidental inheritance of the class. Using the abstract modifier with a sealed class is not permitted. A sealed C# class is similar to a final Java class.

new

Used only with nested classes, new indicates that the class hides an inherited member of the same name.

4.2.2 Class Access Modifiers and Inheritance

Inheritance places some restrictions on the type of access modifiers that can be put on a class. In Java, a class that has default package-level access can have a subclass that is public, as shown here:

//Test.java
package com.acme;
class Test {}
//Test2.java
package com.acme;
public class Test2 extends Test {}

These two classes compile without any errors. In C#, a subclass of a public class either can be public or can have default access (no access modifier specified). A subclass of a class with default access level cannot be public.

Access modifiers on classes dictate the manner in which classes interact and are deployed or exposed to the end user. In Java, classes that are to be part of the public API are declared as public, as is the case with most of the Java API classes and any third-party library distributed as a .jar file. Classes that are used by these public classes but are not necessarily relevant to the end user have package-level access. Furthermore, some classes have private nested classes for situations when the nested private class makes sense only in the scope of the outer class.

If you anticipate that the classes you write are generic enough to be shipped as a library, you should consider carefully which classes you want to expose to the users of the library. If a given class has the default class access, classes in other assemblies cannot access it. This default access should be good enough for most applications.

Next, we discuss the keywords associated with class members such as constructors, methods, fields, and properties. We briefly look at how inheritance affects these members.

    [ directory ] Previous Section Next Section