Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mystery of the Hidden Java Inner Class That Doesn't Exist

I'm working on a transcript project for school, and it's compiling as if there's an anonymous inner class, but I haven't written any. Why is javac compiling an inner class without there being any inner classes (including enums or exceptions) written? The file in question is SemesterInfo$1.class, compiled from SemesterInfo.java. I've seen similar questions where there actually have been inner classes, but there are none here. I throw one exception from the Java library (UnsupportedOperationException), but it's already defined inside the library (java.lang.UnsupportedOperationException) and is therefore not anonymous or an inner class. My directory is as follows:

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
}
like image 467
BrainFRZ Avatar asked Sep 25 '22 07:09

BrainFRZ


1 Answers

This is caused by your switch statement switching on an enum value.

The $1 class file contains a static helper array called a switchmap (a kind of lookup table) to determine at runtime to which bytecode location to jump for each case, based on the enum ordinals. If you decompile it, the beginning looks like this:

$ 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)

See also Java enum and additional class files:

Javac 1.5 and 1.6 [and most likely beyond] create an additional synthetic class each time you use a switch on an enum

like image 76
Andreas Fester Avatar answered Oct 11 '22 04:10

Andreas Fester