不存在的隐藏Java内部类的奥秘

时间:2016-02-20 19:38:39

标签: java javac anonymous-inner-class

我正在为学校制作一份成绩单项目,而且它的编写好像有一个匿名的内部课程,但我还没有写过。为什么javac在没有编写任何内部类(包括枚举或异常)的情况下编译内部类?有问题的文件是SemesterInfo $ 1.class,由SemesterInfo.java编译。我见过类似的问题,其中实际上有内部课程,但这里没有。我从Java库中抛出一个异常(UnsupportedOperationException),但它已在库(java.lang.UnsupportedOperationException)中定义,因此不是匿名或内部类。我的目录如下:

02/20/2016  02:03 PM               915 AddResult.class
02/15/2016  09:16 PM               848 AddResult.java
02/20/2016  02:03 PM             1,032 Console.class
02/05/2016  08:27 AM             1,315 Console.java
02/20/2016  02:03 PM             1,624 CourseInfo.class
02/19/2016  10:56 AM             9,203 CourseInfo.java
02/20/2016  02:03 PM             2,244 CourseInfoTester.class
02/17/2016  05:15 PM             2,226 CourseInfoTester.java
01/22/2016  10:55 AM             3,769 Keyboard.class
02/20/2016  02:03 PM               686 SemesterInfo$1.class
02/20/2016  02:03 PM             6,810 SemesterInfo.class
02/20/2016  01:57 PM            36,263 SemesterInfo.java
02/20/2016  02:03 PM             1,350 SemesterInfoTester.class
02/17/2016  11:59 PM             1,050 SemesterInfoTester.java

SemesterInfo.java

import java.util.Scanner;

public class SemesterInfo
{
    public static int MAX_COURSES       = 7;
    public static int MAX_CREDITS       = 18;
    private static String WITHDRAWN     = "W";
    private static int NOT_FOUND        = -1;

    protected String name;
    protected int creditHours;
    protected int completedCourses;
    protected int courseCount;

    private Scanner input = new Scanner(System.in);

    protected CourseInfo[] courseList;


    /**********************************************************************************************
     * This builds an empty semester using the given name.
     **********************************************************************************************/
    SemesterInfo(String name)
    {
        this.name    = name;
        creditHours  = 0;
        completedCourses  = 0;
        courseCount = 0;
        courseList   = new CourseInfo[MAX_COURSES];
    }


    /**********************************************************************************************
     * This will confirm if a requested semester name is valid. A valid semester must have the
     *     season as the first word and year as the second word. The year must be between 1900
     *     and 9999. The season is not currently case sensitive, although it is recommended to
     *     have the season match Title Case (i.e. "Spring" instead of "spring").
     **********************************************************************************************/
    public static boolean isValidSemester(String name)
    {
        final int MIN_YEAR = 1900;
        final int MAX_YEAR = 9999;

        boolean valid;
        String[] words = name.split(" ");
        int year;

        if (words.length != 2)
        {
            valid = false;
        }
        else if (!words[0].equalsIgnoreCase("Summer") && !words[0].equalsIgnoreCase("Fall")
                    && !words[0].equalsIgnoreCase("Winter") && !words[0].equalsIgnoreCase("Spring"))
        {
            valid = false;
        }
        else
        {
            try
            {
                year = Integer.parseInt(words[1]);

                if (year < MIN_YEAR || year > MAX_YEAR)
                {
                    valid = false;
                }
                else
                {
                    valid = true;
                }
            }
            catch (NumberFormatException e)
            {
                valid = false;
            }
        }

        return valid;
    }


    /**********************************************************************************************
     * This will add a new course to the semester's list. If the current semester is already full
     *     of courses, the method will return a false value.
     **********************************************************************************************/
    public AddResult addCourse(CourseInfo course)
    {
        AddResult result;

        if (completedCourses >= MAX_COURSES)
        {
            result = AddResult.EXCEEDS_COURSE_MAX;
        }
        else if (creditHours + course.creditHours > MAX_CREDITS)
        {
            result = AddResult.EXCEEDS_CREDIT_MAX;
        }
        else if (searchCourse(course.prefix, course.courseNumber) != NOT_FOUND)
        {
            result = AddResult.REDUNDANT;
        }
        else
        {
            courseList[courseCount] = course;

            if (!course.wasWithdrawn())
            {
                completedCourses++;
                creditHours += course.creditHours;
            }

            courseCount++;

            result = AddResult.SUCCESS;

        }

        return result;
    }


    /**********************************************************************************************
     * This removes a course by name if it exists in the course list, and returns whether the
     *     course was successfully removed.
     **********************************************************************************************/
    public boolean removeCourse(String prefix, String number)
    {
        boolean removed;
        int location = searchCourse(prefix, number);

        if (location == NOT_FOUND)
        {
            removed = false;
        }
        else
        {
            if (!courseList[location].wasWithdrawn())
            {
                completedCourses--;
                creditHours -= courseList[location].creditHours;
            }

            courseCount--;

            for (int i = location; location < courseCount; i++)
            {
                courseList[i] = courseList[i+1];
            }

            removed = true;

        }

        return removed;
    }


    /**********************************************************************************************
     * This will allow a course to be withdrawn after it's been entered. Once a course has been
     *     withdrawn, it can't be re-added, but will stay on the transcript as withdrawn.
     **********************************************************************************************/
    public boolean withdrawCourse(String prefix, String number)
    {
        boolean withdrawn;
        int location = searchCourse(prefix, number);

        if (location == NOT_FOUND)
        {
            withdrawn = false;
        }
        //This can't be a combined check in case location doesn't exist (-1 index)
        else if (courseList[location].wasWithdrawn())
        {
            withdrawn = false;
        }
        else
        {
            creditHours -= courseList[location].creditHours;
            completedCourses--;
            courseList[location].withdraw();
            withdrawn = true;
        }

        return withdrawn;
    }


    /**********************************************************************************************
     * This will search the course list for the title of the course given, and returns the index
     *     of the course. If the course isn't found, -1 is returned.
     **********************************************************************************************/
    public int searchCourse(String prefix, String number)
    {
        int index;
        boolean found = false;

        for (index = 0; index < courseCount && !found; index++)
        {
            if (courseList[index].prefix.equalsIgnoreCase(prefix)
                    && courseList[index].courseNumber.equalsIgnoreCase(number))
            {
                found = true;
            }
        }

        if (!found)
        {
            index = 0;
        }

        return (index - 1);
    }


    /**********************************************************************************************
     * This will prompt the user for the list of courses taken in the semester, using the console
     *     for input and output. This method then creates Course objects for each course created,
     *     and adds it to the SemesterInfo object using the addCourse method.
     **********************************************************************************************/
    public void promptCourseList(String quitStr) throws UnsupportedOperationException
    {
        final int MAX_PREFIX_LEN     = 3;
        final int MAX_COURSENUM_LEN  = 4;

        AddResult result;
        CourseInfo course;
        String prefix;
        String number;
        double grade;
        String gradeStr;
        int credits;
        boolean withdrawn;

        if (completedCourses == MAX_COURSES)
        {
            System.out.println("Student is already taking the maximum number of courses!\n");
        }
        else if (creditHours == MAX_CREDITS)
        {
            System.out.println("Student is already taking the maximum number of credits!\n");
        }
        else
        {
            System.out.print("\tEnter a course prefix (\"" + quitStr + "\" when done): ");
            prefix = input.nextLine().toUpperCase();

            while (!prefix.equalsIgnoreCase(quitStr) && completedCourses < MAX_COURSES)
            {
                withdrawn = false;

                while (prefix.isEmpty() || prefix.length() > MAX_PREFIX_LEN)
                {
                    System.out.print("\tInvalid prefix.\nEnter a course prefix (1-" + MAX_PREFIX_LEN
                                        + " characters): ");
                    prefix = input.nextLine().toUpperCase();
                }

                System.out.print("\tEnter a course number:                    ");
                number = input.nextLine().toUpperCase();

                while (number.isEmpty() || number.length() > MAX_COURSENUM_LEN)
                {
                    System.out.print("\tInvalid number.\nEnter a course number (1-"
                                        + MAX_COURSENUM_LEN + " characters): ");
                    number = input.nextLine().toUpperCase();
                }

                System.out.print("\tEnter credit hours:                       ");
                credits = Integer.parseInt(input.nextLine());

                while (credits < CourseInfo.MIN_CREDITS || credits > CourseInfo.MAX_CREDITS)
                {
                    System.out.print("\tInvalid number.\nEnter credit hours (1 - "
                                            + CourseInfo.MAX_CREDITS + "): ");
                    credits = Integer.parseInt(input.nextLine());
                }

                System.out.print("\tEnter grade point (\"" + WITHDRAWN + "\" if withdrawn):     ");
                gradeStr = input.nextLine();

                if (gradeStr.equalsIgnoreCase(WITHDRAWN))
                {
                    withdrawn = true;
                    grade = CourseInfo.MIN_GRADE_POINT;
                }
                else
                {
                    try
                    {
                        grade = Double.parseDouble(gradeStr);
                    }
                    catch (NumberFormatException e)
                    {
                        grade = CourseInfo.MIN_GRADE_POINT - 1;
                    }
                }

                while (grade < CourseInfo.MIN_GRADE_POINT || grade > CourseInfo.MAX_GRADE_POINT)
                {
                    if (gradeStr.equalsIgnoreCase(WITHDRAWN))
                    {
                        withdrawn = true;
                        grade = CourseInfo.MIN_GRADE_POINT;
                    }
                    else
                    {
                        try
                        {
                            grade = Double.parseDouble(gradeStr);
                        }
                        catch (NumberFormatException e)
                        {
                            grade = CourseInfo.MIN_GRADE_POINT - 1;
                        }
                    }

                    if (grade < CourseInfo.MIN_GRADE_POINT || grade > CourseInfo.MAX_GRADE_POINT)
                    {
                        System.out.print("\tInvalid number.\nEnter grade point (\"" + WITHDRAWN
                                            + "\" or 0.0 - " + CourseInfo.MAX_GRADE_POINT + "): ");
                        grade = Double.parseDouble(input.nextLine());
                    }
                }

                if (withdrawn)
                {
                    course = new CourseInfo(prefix, number, credits);
                }
                else
                {
                    course = new CourseInfo(prefix, number, grade, credits);
                }

                result = addCourse(course);

                switch (result) {
                    case SUCCESS:
                        System.out.println("\tSuccessfully added " + course.prefix + "-"
                                            + course.courseNumber);
                        break;
                    case REDUNDANT:
                        System.out.println("\tCourse was already entered.");
                        break;
                    case EXCEEDS_COURSE_MAX: //Shouldn't happen, since prompting should end first
                        System.out.println("\tStudent is already taking a full course load!");
                        break;
                    case EXCEEDS_CREDIT_MAX:
                        System.out.println("\tStudent is already taking too many credits ("
                                            + creditHours + " of " + MAX_CREDITS + ")!");
                        break;
                    default:
                        throw new UnsupportedOperationException("\tUnknown error occurred while "
                                                                   + "adding course: " + result);
                }

                if (completedCourses < MAX_COURSES)
                {
                    System.out.print("\n\tEnter a course prefix (\"" + quitStr + "\" when done): ");
                    prefix = input.nextLine().toUpperCase();
                }
            }
        }
    }


    /**********************************************************************************************
     * This will calculate the GPA of all courses currently in the semester.
     **********************************************************************************************/
    public double calcGPA()
    {
        double totalGradePoint = 0.0;

        for (int i = 0; i < courseCount; i++)
        {
            if (!courseList[i].wasWithdrawn())
            {
                totalGradePoint += courseList[i].calcGradePoint();
            }
        }

        return (totalGradePoint / creditHours);
    }


    /**********************************************************************************************
     * This will display the entire semester's course list and GPA in tabular format, centered to
     *     a window 80 characters wide.
     **********************************************************************************************/
    public void displaySemester()
    {
        String gpaString;

        if (courseCount == 0)
        {
            System.out.println("                    No courses were taken this semester.");
        }
        else
        {
            System.out.println("                " + name);
            System.out.println("                    Course      Grade    Credits    Grade Point");


            for (int i = 0; i < courseCount; i++)
            {
                System.out.println("                    " + courseList[i].toString());
            }

            if (completedCourses < 1)
            {
                gpaString = "GPA:  N/A";
            }
            else
            {
                gpaString = String.format("GPA: %4.2f", calcGPA());
            }

            System.out.println("                                                      " + gpaString);
        }

        System.out.println();
    }


    /**********************************************************************************************
     * This method will display the semester details on a single line in tabular format for the
     *     following expected table example:
     *              Semester Date   Courses    Credits     GPA
     *              Fall 2016          4         15       4.00
     *     There is no padding on either side of the string, and no new line at end of line.
     **********************************************************************************************/
    @Override
    public String toString()
    {
        String gpa;

        if (completedCourses != 0)
        {
            gpa = String.format("%4.2f", calcGPA());
        }
        else
        {
            gpa = "N/A";
        }

        return String.format("%-13s      %1d         %2d       %4s", name, completedCourses,
                                creditHours, gpa);
    }
}

CourseInfo.java

/**************************************************************************************************
 * Program Description: This class holds the information for a specific course.
 **************************************************************************************************/

public class CourseInfo
{
    public static int MIN_CREDITS        = 1;
    public static int MAX_CREDITS        = 4;
    public static double MIN_GRADE_POINT = 0.0;
    public static double MAX_GRADE_POINT = 4.0;

    protected String prefix;
    protected String courseNumber;
    protected int creditHours;
    protected double grade;
    private boolean withdrawn;


    /**********************************************************************************************
     * This constructor will assign the course prefix, course number, grade and credits when a
     *     course was not withdrawn.
     **********************************************************************************************/
    public CourseInfo(String prefix, String number, double grade, int credits)
    {
        this.prefix     = prefix;
        courseNumber    = number;
        this.grade      = grade;
        creditHours     = credits;
        withdrawn = false;
    }


    /**********************************************************************************************
     * This constructor will assign the course prefix, course number, grade and credits when a
     *     course was not withdrawn.
     **********************************************************************************************/
    public CourseInfo(String prefix, String number, int credits)
    {
        this.prefix = prefix;
        courseNumber = number;
        grade = 0.0;
        creditHours = credits;
        withdrawn = true;
    }


     /**********************************************************************************************
     * This method will calculate the grade point, multiplying the credit hours by the grade.
     **********************************************************************************************/
    public double calcGradePoint()
    {
        return (creditHours * grade);
    }


    /**********************************************************************************************
     * This method will tell whether the course was withdrawn or not.
     **********************************************************************************************/
    public boolean wasWithdrawn()
    {
        return withdrawn;
    }


    /**********************************************************************************************
     * This method will withdraw the course
     **********************************************************************************************/
    public void withdraw()
    {
        withdrawn = true;
        grade = 0.0;
        creditHours = 0;
    }


    /**********************************************************************************************
     * This method will display the course details on a single line in tabular format for the
     *     following expected table example:
     *         Course      Grade    Credits    Grade Point
     *         CSC-264      4.0        4             16.00
     *     There is no padding on either side of the string, and no new line at end of line.
     **********************************************************************************************/
    @Override
    public String toString()
    {
        String str;

        if (wasWithdrawn())
        {
            str = String.format("%3s-%-4s        W          %1d            N/A", prefix,
                                    courseNumber, creditHours);
        }
        else
        {
            str = String.format("%3s-%-4s     %4.2f          %1d          %5.2f", prefix,
                                    courseNumber, grade, creditHours, calcGradePoint());
        }

        return str;
    }
}

AddResult.java

public enum AddResult
{
    SUCCESS,                //Course/Semester was added successfully
    EXCEEDS_COURSE_MAX,     //Student is already taking too many courses
    EXCEEDS_CREDIT_MAX,     //Student is already taking too many credits
    REDUNDANT               //Course/Semester already exists
}

1 个答案:

答案 0 :(得分:4)

这是由switch语句切换enum值引起的。

$1类文件包含一个名为switchmap(一种查找表)的静态辅助数组,用于根据枚举确定运行时每个case要跳转的字节码位置。如果你反编译它,开头看起来像这样:

$ javap -c SemesterInfo$1.class
Compiled from "SemesterInfo.java"
class SemesterInfo$1 {
  static final int[] $SwitchMap$AddResult;

  static {};
    Code:
       0: invokestatic  #1                  // Method AddResult.values:()[LAddResult;

    ... Additional code which initializes the array (static initializer)

另见Java enum and additional class files

  

Javac 1.5和1.6 [很可能超越]每次在枚举上使用开关时都会创建一个额外的合成类